Spring IOC的元件註冊、依賴注入的實現方式
IOC—Inversion of Control,控制反轉,它是一種設計思想,它能指導程式設計師如何設計出鬆耦合、更優良的程式程式碼。
如果不用IOC,建立、銷燬物件、物件之間的依賴關係,都需要程式設計師自己在程式碼裡面體現,各種new。
而有了IOC容器後,程式碼裡只需要定義物件的基本資訊,並將它註冊到IOC容器中,讓IOC管理它的生命週期(建立和銷燬)以及它們之間的依賴關係。
第一章:將元件(物件)新增到ioc容器的四種方式
第一節:bean方式(註解和xml兩種方式)
第二節:bean工廠方式(靜態工廠、例項化工廠兩種)
第三節:包掃描
第四節:@Import註解快速註冊
第五節(拓展):@Conditional 根據條件判斷bean是否可以新增到容器中,Spring底層經常使用
第六節(拓展):@profile 根據當前環境,動態的啟用和切換一系列元件
第二章:自動裝配實現方式(即DI 依賴注入實現屬性賦值)
第七節:@Autowired 自動裝配
第八節:JSR-250(java規範)的註解@Resource
第九節:xml配置實現裝配的多種方式
第十節(拓展):自定義元件實現xxxAware介面,使用spring底層的一些元件(BeanFactory、ApplictionContext等)
Action one:建立maven專案,新增spring和junit依賴:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.12.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
第一節:bean方式註冊元件
>定義User物件
public class User {
public User() {
super();
}
public User(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
>xml方式實現註冊
<bean id="user" class="com.mote.pojo.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="22"></property>
</bean>
>註解方式實現註冊
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mote.pojo.User;
//@Configuration 標註這是一個註解配置類,該類就相當於spring的配置檔案applictionContext.xml
@Configuration
public class MainConfig {
/**
* @Bean表示向IOC容器中註冊bean,value指定bean名稱,如果不指定,預設使用方法名
*/
@Bean(value="user")
public User user(){
return new User("lisi",25);
}
}
>測試類
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mote.config.MainConfig;
import com.mote.pojo.User;
public class MainTest {
@Test //註解測試
public void testAnnotation(){
//載入Spring註解配置類
AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
//從容器中獲取bean
User user = application.getBean(User.class);
System.out.println(user);
}
@Test //xml測試
public void testXml(){
//載入Spring-xml配置檔案
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
//從容器中獲取bean
User user = application.getBean(User.class);
System.out.println(user);
}
}
>列印結果:
第二節:bean工廠方式(靜態工廠、例項化工廠兩種)
1:靜態工廠模式:工廠類本身不需要例項化, 通過工廠類直接呼叫其中的靜態方法生成bean物件。
定義物件Car:
public class Car {
private String name;
private double money;
public Car() {
super();
}
public Car(String name, double money) {
super();
this.name = name;
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Car [name=" + name + ", money=" + money + "]";
}
}
定義生產Car的靜態工廠:
public class CarFactory {
/**
* 靜態方法,返回Car例項
* @return
*/
public static Car getCar(){
return new Car("寶馬",10000000.00);
}
}
配置xml:
<!-- 配置Car工廠,呼叫getCar(),返回Car例項 -->
<bean id="car" class="com.mote.pojo.CarFactory" factory-method="getCar"></bean>
測試列印:
public class MainTest {
@Test //註解測試
public void testAnnotation(){
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
Car car = application.getBean(Car.class);
//Car car1 = (Car) application.getBean("car");
System.out.println(car);
}
}
2:例項工廠模式:因為getCar方法不是靜態的,需要先例項化CarFactory工廠,在通過carFactory呼叫getCar生產bean物件
定義物件Car:(和靜態工廠模式的測試一致)
定義Car的例項化工廠:
public class CarFactory {
public Car getCar(){
return Car("寶馬",10000000.00);
}
}
配置xml:
<!-- 配置Car工廠-->
<bean id="carFactory" class="com.mote.pojo.CarFactory"></bean>
<!-- 呼叫carFactory的getCar,配置car的例項 -->
<bean id="car" factory-bean="carFactory" factory-method="getCar"></bean>
測試列印:(和靜態工廠模式的測試一致)
第三節:包掃描[email protected]、@Service、@Repository、@Component(註解和xml兩種方式)
>定義UserController,UserService,UserDao,UserTest,分別加上述註解
>專案目錄結構:
>xml方式實現包掃描註冊
<!-- 開啟包掃描 ,指定的包以及子包下 只要標註了@Controller、@Service、@Repositoy、@Component
的類都會被新增到spring容器中-->
<context:component-scan base-package="com.mote"/>
>註解方式實現包掃描註冊
@Configuration
//@ComponentScan 開啟包掃描,value指定包名
@ComponentScan(value = "com.mote")
public class MainConfig {
}
>測試類
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mote.config.MainConfig;
public class MainTest {
@Test //註解測試
public void testAnnotation(){
//載入Spring註解配置類
AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
//獲取註冊到容器中的元件name集合,遍歷列印
String[] names = application.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
@Test //xml測試
public void testXml(){
//載入Spring-xml配置檔案
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
String[] names = application.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
>列印結果
第四節:@Import註解快速註冊
Import註解實現註冊有三種實現方式
1:@Import(要新增的元件)
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.mote.dao.UserDao;
import com.mote.service.UserService;
@Configuration
//@Import 快速給容器中匯入一個元件,預設id是全類名
//@Import(UserController.class) //註冊一個
@Import({UserService.class,UserDao.class}) //註冊多個
public class MainConfig {
}
2:實現ImportSelector介面,自定義返回要註冊的元件
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImport implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] { "com.mote.controller.UserService","com.mote.dao.UserDao" };
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(MyImport.class)
public class MainConfig {
}
3:實現ImportBeanDefinitionRegistrar介面,實現手動註冊
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import com.mote.dao.UserDao;
public class MyImport implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:當前類的註解資訊
* BeanDefinitionRegistry:BeanDefinition註冊類
*/
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
//判斷容器中是否註冊userDao
boolean flag = registry.containsBeanDefinition("userDao");
//向容器中註冊bean,並指定bean_name為userDao
BeanDefinition beanDefinition = new RootBeanDefinition(UserDao.class);
registry.registerBeanDefinition("userDao", beanDefinition );
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(MyImport.class)
public class MainConfig {
}
>測試類
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mote.config.MainConfig;
public class MainTest {
@Test //註解測試
public void testAnnotation(){
//載入Spring註解配置類
AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
//獲取註冊到容器中的元件name集合,遍歷列印
String[] names = application.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
>列印結果
方式一:
方式二:
方式三:
第五節(拓展):@Conditional 根據條件判斷bean是否可以新增到容器中,Spring底層經常使用
需求描述:如果當前系統是Windows,註冊User(“bier”,30),反之不註冊
1:實現Condition介面,書寫判斷邏輯
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyConditional implements Condition{
/**
* ConditionContext:判斷條件使用的上下文
* AnnotatedTypeMetadata:註釋資訊
*/
public boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
//獲取當前執行環境資訊
Environment environment = context.getEnvironment();
//獲取當前系統型別,判斷是否是Windows
String type = environment.getProperty("os.name");
return type.contains("Windows")?true:false;
}
}
2:使用@Conditional註解進行判斷
import com.mote.pojo.User;
@Configuration
public class MainConfig {
@Bean
@Conditional({MyConditional.class})
public User bier(){
return new User("bier",30);
}
}
小技巧:eclipse模擬linux環境
測試類中點選滑鼠右鍵,Run AS > RunConfigurations
測試:
public class MainTest {
@Test //註解測試
public void test(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = context.getBeanDefinitionNames(); //列印spring容器註冊的bean名稱
for (String name : names) {
System.out.println(name);
}
}
}
windows環境執行結果列印:
linux系統執行結果列印:
第六節(拓展):@profile 根據當前環境,動態的啟用和切換一系列元件
案例功能描述:根據當前環境決定使用相應的資料庫
* 預設情況下:資料庫A
* 測試環境下:資料庫B
* 開發環境下:資料庫C
匯入maven:dhcp連線池和mysql驅動
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
案例程式碼:
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
/**
* @Profile:加了該環境標識的bean,只有這個環境被啟用後後才能註冊到容器
*/
@Configuration
public class MainConfig {
@Bean
@Profile("default") //不指定的情況下,預設使用的資料庫
public BasicDataSource dataSourceDefault() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/A");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
@Profile("test") //測試環境
public BasicDataSource dataSourceTest() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/B");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
@Profile("devlop") //開發環境
public BasicDataSource dataSourceDev() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/C");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}
測試程式碼:
public class MainTest {
@Test //註解測試
public void test(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
測試一:不指定環境變數,直接執行,列印如下
測試二:指定環境為test,執行列印
列印結果:
第七節:@Autowired 自動裝配
@Autowired使用前提,userService已經註冊到spring容器中
@Autowired實現裝配的三種操作方式
1)標註在屬性上
/**
* @Autowired 首先根據UserService型別去容器尋找Bean,
* 如果這個型別有多個Bean,比如userService/userService1
* 那麼@Autowired就會根據屬性名稱userService去匹配.
*
* 另外,可以使用註解@Qualifier配合@Autowired使用,用於指定容器中特定id的Bean
*/
//@Qualifier("userService")
@Autowired
private UserService userService;
2)標註在set方法上
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
3)標註在構造器上
private UserService userService;
/**
* 如果該類只有這一個構造器,那麼這個@Autowired註解可以省略不寫
* 因為spring容器生成的時候,就必須根據這個構造器去建立物件
*/
@Autowired
public UserController(UserService userService) {
super();
this.userService = userService;
}
第八節:JSR-250(java規範)的註解@Resource
@Resource使用前提,userService已經註冊到spring容器中
/**
* @Resource JSR-250註解,用來啟用資源,通過name屬性,指定容器中特定id的bean
*/
@Resource(name="userService")
private UserService userService;
第九節:xml配置實現裝配的多種方式
1)set方法注入依賴
xml:
<bean id="userService" class="com.mote.service.UserService"/>
<bean class="com.mote.controller.UserController">
<property name="userService" ref="userService"/>
</bean>
程式碼:
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
2)構造器注入依賴
xml:
<bean id="userService" class="com.mote.service.UserService"></bean>
<bean class="com.mote.controller.UserController">
<constructor-arg name="userService" ref="userService"></constructor-arg>
</bean>
程式碼:
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
3)靜態工廠注入依賴和例項化工廠注入依賴
這兩種方式其實就是通過set方法注入依賴,只是向容器中新增bean的方式不同。
第十節(拓展):自定義元件實現xxxAware介面,使用spring底層的一些元件
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class MyAware implements ApplicationContextAware,BeanFactoryAware {
private ApplicationContext applicationContext; //設定成員變數
private BeanFactory beanFactory; //設定成員變數
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext; //賦值
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory; //賦值
}
public void test(){
//使用 applicationContext、beanFactory
}
}
相關推薦
Spring IOC的元件註冊、依賴注入的實現方式
IOC—Inversion of Control,控制反轉,它是一種設計思想,它能指導程式設計師如何設計出鬆耦合、更優良的程式程式碼。 如果不用IOC,建立、銷燬物件、物件之間的依賴關係,都需要程式設計師自己在程式碼裡面體現,各種new。 而有了IOC容器後,程式碼裡只需
使用XPath解析xml實現簡單的Spring IOC完成bean的依賴注入
幾天使用Xpath解析xml檔案,例項化bean,完成spring IOC bean的依賴注入的簡單實現。 假設用如下格式的bean檔案: <?xml version="1.0" encoding="UTF-8"?> <beans> <b
深入研究Spring-IoC:原始碼分析依賴注入
1.前言 對於容器建立的過程已經闡述過一遍了,下面是依賴注入的問題。Spring提供的依賴注入的方法主要由兩種:一種是通過getBean的方法;另一種是通過註解@Autowaire。 需要指出的是依賴注入的過程是使用者第一次向ioc容器索要Bean的時候開始生產的,也可以通過設定
深入淺出spring IOC中三種依賴注入方式
首先:第一個問題,參與者都有誰?1)物件2)IOC/DI容器3)某個物件的外部資源第二問題:依賴,誰依賴誰?為什麼需要依賴?依賴嘛,很好理解的,物件依賴於IOC/DI容器,至於為什麼要依賴呢?物件需要IOC/DI容器來提供物件需要的外部資源。第三個問題:注入,誰注入誰?又注入了什麼呢?顯而易見是IOC/DI容
spring IOC中三種依賴注入方式 經典總結
首先:第一個問題,參與者都有誰?1)物件2)IOC/DI容器3)某個物件的外部資源第二問題:依賴,誰依賴誰?為什麼需要依賴?依賴嘛,很好理解的,物件依賴於IOC/DI容器,至於為什麼要依賴呢?物件需要IOC/DI容器來提供物件需要的外部資源。第三個問題:注入,誰注入誰?又注入了什麼呢?顯而易見是IOC/DI容
對spring IOC(控制翻轉) DI(依賴注入)AOP(面向切面)理解
(1) 控制反轉(Inversion of Confrol): 物件的建立交給外部容器完成,這個就叫做控制反轉, Ioc—Inversion of Control,即“控制反轉”,不是什麼技術,而是一種設計思想。在Java開發中,Ioc意味著將你設計好的物件交給容器控
Spring IoC是如何進行依賴注入的
## 依賴注入(DI) **DI(Dependency Injection)**,Spring IoC 不是一種技術,而是一種思想,通過這種思想,能夠指導我們設計出鬆耦合的程式程式碼。而Spring IoC這個思想的作用體現在兩個方面,一是如何將Bean裝配到容器中去以及如何從容器中獲取Bean,二是如何解
Spring系列教程五: 依賴注入的方式詳解
依賴注入的概念 Spring中的依賴注入,稱為dependency Injection,Ioc的作用降低程式之間的耦合,依賴關
Spring IOC/BeanFactory/ApplicationContext的工作流程/實現原理/初始化/依賴注入原始碼詳解
Spring的工作流程/實現原理之基石IOC/BeanFactory/ApplicationContext 更新1:2017/11/23更新2:2018/1/30(截圖)一、什麼是IOC容器?IOC(Inversion of Control)、控制反轉亦稱依賴注入.IOC容器
控制反轉IOC的依賴注入方式 【調侃】IOC前世今生 IoC模式 談談對Spring IOC的理解 一個簡單的小程式演示Unity的三種依賴注入方式 小菜學習設計模式(五)—控制反轉(Ioc) IoC模式(依賴、依賴倒置、依賴注入、控制反轉) IoC模式
轉自:https://www.cnblogs.com/ysyn/p/5563256.html 引言: 專案中遇到關於IOC的一些內容,因為和正常的邏輯程式碼比較起來,IOC有點反常。因此本文記錄IOC的一些基礎知識,並附有相應的簡單例項,而在實際專案中再複雜的應用也只是在
Spring入口_Bean的註冊與依賴注入
一、Spring入口  
Spring 依賴注入實現原理--java反射和ASM框架
依賴注入是spring的一個特性,從配置層面解決了程式耦合、依賴問題,spring提供了建構函式依賴注入、Setter方法依賴注入、自動裝配依賴注入和@autowired註解依賴注入等多種實現方式。 那麼依賴注入是如何實現的?第一反應就是java反射唄,比如建構
3.Spring與IoC-基於XML的依賴注入(DI)
Bean例項在呼叫無參構造器建立了空值物件後,就要對Bean物件的屬性進行初始化。初始化是由容器自動完成的,成為注入。根據注入方式的不同,常用的有兩類:設值注入、構造注入。 還有一種實現特定介面的注入。由於採用侵入式程式設計,汙染程式碼,所以幾乎不用 記住:
(一)Spring IoC原始碼-3.其他特性的實現原理-02迴圈依賴的解決
引言:迴圈依賴就是N個類中迴圈巢狀引用,如果在日常開發中我們用new 物件的方式發生這種迴圈依賴的話程式會在執行時一直迴圈呼叫,直至記憶體溢位報錯。下面說一下Spring是如果解決迴圈依賴的。 第一種:構造器引數迴圈依賴 Spring容器會將每一個正
Spring 使用註解完成bean例項化、依賴注入的相關配置以及注意事項
一、 相關配置例項化註解介紹 首先使用註解完成spring容器例項的配置,主要用到以下幾個: 1、@Repository(“name”):配置持久層例項bean,通常用在DAO; 這裡配置的name屬性相當於在 2、@Servic
巧妙運用spring依賴注入實現簡單工廠模式
舉一個業務場景: 假設有一個統一買票旅遊的入口,買完票會有一個欄位表明種類。 這些種類表明你去哪,怎麼去。 是坐飛機去奧地利,或是走路到隔壁龍蝦店,都不得而知,而且程式碼邏輯幾乎沒有關聯。這個時候我們難道要這樣寫程式碼嗎? if(type == 1){
Spring筆記之七(Types of Injection) Spring的三種依賴注入實現型別
本文研究Spring的三種依賴注入實現型別——介面注入(Interface Injection)、設值注入(Setter Injection)、構造子注入(Constructor Injection)。 Type1 介面注入: 傳統的建立介面物件的方法, 藉助介面來將呼叫者與
spring中依賴注入的方式及實現(2)
依賴注入的方式1、屬性注入2、構造器注入3、工廠方法注入(很少使用,不推薦)1、屬性注入(1)屬性注入即通過 setter 方法注入Bean 的屬性值或依賴的物件(2)屬性注入使用 <proper
依賴倒置原則(DIP)、控制反轉(IoC)、依賴注入(DI)(C#)
理解: 依賴倒置原則(DIP)主程式要依賴於抽象介面,不要依賴於具體實現。高層模組不應該依賴底層模組,兩個都應該以來抽象。抽象不應該依賴細節,細節應該依賴抽象。(具體看我上一篇貼子) 依賴倒置原則是六大設計原則中的一種,它的大致意思是所有模組都應該依賴於抽象,而不是直接依賴於另一個模組。依賴倒置原則僅僅只是一
.NET IoC模式依賴反轉(DIP)、控制反轉(Ioc)、依賴注入(DI)
# 依賴倒置原則(DIP) 依賴倒置(Dependency Inversion Principle,縮寫DIP)是面向物件六大基本原則之一。他是指一種特定的的解耦形式,使得高層次的模組不依賴低層次的模組的實現細節,依賴關係被顛倒(反轉),從而使得低層次模組依賴於高層次模組的需求抽象. 該原則規定: -