目錄
承接上文:詳解Spring IoC&DI (一)
1.IoC詳解
1.1方法注解@Bean
1.2方法注解要配合類注解使用?
1.3定義多個對象
1.4重命名Bean
1.5掃描路徑
2.DI詳解
2.1DI與IoC的關系
2.2屬性注入
2.3構造方法注入
?2.4Setter注入
2.5?三種注入優缺點分析
2.6Autowired存在問題
2.6.1Primary
?2.6.2Qualifier
2.6.3Resource
承接上文:詳解Spring IoC&DI (一)
1.IoC詳解
1.1方法注解@Bean
類注解是添加到某個類上的?,?但是存在兩個問題:
1.使?外部包?的類,?沒辦法添加類注解
2.?個類, 需要多個對象, 比如多個數據源
這種場景,?我們就需要使??法注解@Bean
代碼示例:
public class BeanConfig { @Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}}
當我們寫完以上代碼?,嘗試獲取 bean 對象中的 user 時卻發現?,根本獲取不到:
@SpringBootApplication
public class TestSpringTwoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class,args);//從Spring上下?中獲取對象User user =context.getBean(User.class);//使?對象System.out.println(user);}
}
執行結果如下:?
1.2方法注解要配合類注解使用?
在 Spring?框架的設計中?,?法注解?@Bean?要配合類注解才能將對象正常的存儲到Spring?容器中
如下代碼所示:
@Componentpublic class BeanConfig { @Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}}
再次執?以上代碼?,運?結果如下:
1.3定義多個對象
多數據源的場景, 類是同?個, 但是配置不同,?指向不同的數據源.
@Component
public class BeanConfig {@Beanpublic User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2(){User user = new User();user.setName("lisi");user.setAge(28);return user;}}
獲取對象:
@SpringBootApplication
public class TestSpringTwoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class, args);//從Spring上下?中獲取對象User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");//使?對象System.out.println(user1);System.out.println(user2);}
}
運行結果:
1.4重命名Bean
可以通過設置 name 屬性給 Bean 對象進?重命名操作?,如下代碼所示:
@Bean(name = {"u1","user1"})public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
此時我們使用u1就可以獲取到User對象:
User u1 = (User) context.getBean("u1");
name={} 可以省略?,如下代碼所?:?
@Bean({"u1","user1"})public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
只有?個名稱時, {}也可以省略, 如:
@Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
1.5掃描路徑
使?前?學習的四個注解聲明的bean想要?效?,還需要被Spring掃描
通過修改項目工程的目錄結構進行測試:
運行結果:
?解釋: 沒有bean的名稱為u1,
使?五?注解聲明的bean?,要想?效, 還需要配置掃描路徑, 讓Spring掃描到這些注解也就是通過
@ComponentScan來配置掃描路徑.
@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class TestSpringTwoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class,args);//從Spring上下?中獲取對象User user =context.getBean(User.class);//使?對象System.out.println(user);}
}
@ComponentScan注解雖然沒有顯式配置,但是實際已經包含在了啟動類聲明注解
@SpringBootApplication中了,默認掃描的范圍是啟動類所在包及其子包
?
2.DI詳解
2.1DI與IoC的關系
DI(Dependency Injection,依賴注入)和 IoC(Inversion of Control,控制反轉)有著密切的關系。 可以說 DI 是實現 IoC 的一種具體方式。 IoC 是一種設計思想,強調將對象之間的控制權進行反轉,不再由對象自己去創建或獲取其依賴,而是由外部(如框架)來控制和管理依賴關系的創建和注入。 而 DI 則側重于具體的將依賴對象注入到目標對象的操作,它是實現 IoC 理念的重要手段之一。通過 DI,依賴對象在合適的時候被準確地注入到需要它們的對象中,從而體現了 IoC 的原則。 簡單來說,IoC 是更宏觀的概念,DI 是實現 IoC 的具體策略和機制。
關于依賴注?, Spring也給我們提供了三種?式:
屬性注?(Field?Injection)、構造?法注?(Constructor?Injection)、Setter?注?(Setter?Injection)
2.2屬性注入
@SpringBootApplicationpublic class SpringIocDemoApplication { public static void main(String[] args) { //獲取Spring上下?對象ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio //從Spring上下?中獲取對象UserController userController = (UserController) context.getBean("userCont //使?對象userController.sayHi(); 11 }}
屬性注?是使用@Autowired實現的?,將 Service?類注?到 Controller?類中.
Service類的實現代碼如下:?
import org.springframework.stereotype.Service; @Servicepublic class UserService {public void sayHi() {System.out.println("Hi,UserService");}}
Controller?類的實現代碼如下:
@Controllerpublic class UserController { //注??法1: 屬性注?@Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}}
獲取Controller中的sayHi方法:?
@SpringBootApplicationpublic class SpringIocDemoApplication { public static void main(String[] args) { //獲取Spring上下?對象ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class,args);//從Spring上下?中獲取對象UserController userController = context.getBean(UserController.class);//使?對象userController.sayHi(); }}
?運行結果為:
2.3構造方法注入
構造方法注入是在類的構造方法中實現注入,如下代碼所示:
@Controller
public class UserController2 { //注??法2: 構造?法private UserService userService; @Autowiredpublic UserController2(UserService userService) {this.userService = userService;} public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}}
注意事項:如果類只有?個構造?法?,那么@Autowired?注解可以省略;如果類中有多個構造?法, 那么需要添加上@Autowired?來明確指定到底使?哪個構造?法。
?2.4Setter注入
Setter?注?和屬性的 Setter?方法實現類似?,只不過在設置 set?方法的時候需要加上@Autowired?注解 ,如下代碼所示:
@Controllerpublic class UserController3 { //注??法3: Setter?法注?private UserService userService; @Autowiredpublic void setUserService(UserService userService) {this.userService = userService;} public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}}
2.5?三種注入優缺點分析
屬性注?
??優點: 簡潔?,使??便;?
??缺點:只能?于 IoC 容器?,并且只有在使?的時候才會出現 NPE(?空指針異常)、?不能注入?個Final修飾的屬性
?構造函數注?(Spring 4.X推薦)?
?優點:可以注?final修飾的屬性、注?的對象不會被修改、依賴對象在使?前?定會被完全初始化?,因為依賴是在類的構造?法中執?的?,?構造?法是在類加載階段就會執?的?法、?通?性好, 構造?法是JDK?持的, 所以更換任何框架,他都是適?的
?缺點:?注入多個對象時, 代碼會比較繁瑣
??Setter注?(Spring?3.X推薦)
?優點: ?便在類實例之后, 重新對該對象進?配置或者注?
缺點:不能注??個Final修飾的屬性、注?對象可能會被改變, 因為setter?法可能會被多次調??, 就有被修改的風險.
2.6Autowired存在問題
當同?類型存在多個bean時, 使?@Autowired會存在問題
@Componentpublic class BeanConfig { @Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;} @Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}}
@Controllerpublic class UserController { //注?user @Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();System.out.println(user);}}
運行結果:?
報錯的原因是?,?唯—的 Bean 對象。
Spring提供了以下幾種解決?案:
2.6.1Primary
@Primary注解:?當存在多個相同類型的Bean注?時?,加上@Primary注解?,來確定默認的實現.
@Componentpublic class BeanConfig { @Primary //指定該bean為默認bean的實現@Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;} @Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}}
?2.6.2Qualifier
指定當前要注?的bean對象。 在@Qualifier的value屬性中?,指定注?的bean 的名稱。
?@Qualifier注解不能單獨使? ,必須配合@Autowired使用
@Controllerpublic class UserController {@Qualifier("user2") //指定bean名稱@Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}}
2.6.3Resource
使?@Resource注解:是按照bean的名稱進?注?。通過name屬性指定要注?的bean的名稱。
@Controllerpublic class UserController { @Resource(name = "user2")private User user; public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}}
@Autowird 與 @Resource的區別
? ?@Autowired?是spring框架提供的注解?,而@Resource是JDK提供的注解
? ?@Autowired 默認是按照類型注??,?@Resource是按照名稱注??. 相?于 @Autowired ?來說,?@Resource??持更多的參數設置?,例如 name 設置?,根據名稱獲取 Bean。