1負(fù)責(zé)注入的注解
負(fù)責(zé)注入的注解,常見的包括四個(gè):
- @Value
- @Autowired
- @Qualifier
- @Resource
1.1 @Value
- 當(dāng)屬性的類型是簡單類型時(shí),可以使用@Value注解進(jìn)行注入。
- @Value注解可以出現(xiàn)在屬性上、setter方法上、以及構(gòu)造方法的形參上, 方便起見,一般直接作用在屬性上.
package com.sunsplanter.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
@Value(value = "zhangsan")
private String name;
@Value("20")
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/*@Value和setter方法結(jié)合
private String name;
private int age;
@Value("李四")
public void setName(String name) {
this.name = name;
}
@Value("30")
public void setAge(int age) {
this.age = age;
}
*/
/*@Value和構(gòu)造方法結(jié)合
private String name;
private int age;
public User(@Value("隔壁老王") String name, @Value("33") int age) {
this.name = name;
this.age = age;
}
*/
}
配置文件開啟包掃描:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.sunsplanter.bean"/>
</beans>
測試程序:
@Test
public void testValue(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Object user = applicationContext.getBean("user");
System.out.println(user);
}
三種方法都可以正確注入簡單類型.
1.2 @Autowired與@Qualifier
- @Autowired注解可以用來注入非簡單類型。被翻譯為:自動(dòng)連線的,或者自動(dòng)裝配。
- @Autowired注解可以出現(xiàn)在構(gòu)造方法上/方法上/形參上/屬性上/注解上
- @Autowired注解有一個(gè)required屬性,默認(rèn)值是true,表示在注入的時(shí)候要求被注入的Bean必須是存在的,如果不存在則報(bào)錯(cuò)。如果required屬性設(shè)置為false,表示注入的Bean存在或者不存在都沒關(guān)系,存在的話就注入,不存在的話,也不報(bào)錯(cuò)。
目標(biāo): 存在兩層: Service層和Dao層. 如前所述,UserService要控制UserDaoForMySQL, 必須要實(shí)例化一個(gè)UserDaoForMySQL的對象并注入到UserService類中定義的UserDaoForMySQL中.
配置Bean后Spring容器幫我們實(shí)例化了這個(gè)對象, 之前也學(xué)過了如何通過配置Bean標(biāo)簽注入. 本節(jié)的目標(biāo)是通過注解完成自動(dòng)注入.
結(jié)構(gòu)為:
Dao層接口UserDao:
package com.dao;
public interface UserDao {
void insert();
}
實(shí)現(xiàn)類UserDaoForMySQL:
package com.dao;
import org.springframework.stereotype.Repository;
@Repository //納入bean管理
public class UserDaoForMySQL implements UserDao{
@Override
public void insert() {
System.out.println("正在向mysql數(shù)據(jù)庫插入U(xiǎn)ser數(shù)據(jù)");
}
}
Service層:
package com.Service;
import com.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service // 納入bean管理
public class UserService {
@Autowired // 在屬性上注入
private UserDao userDao;
// 沒有提供構(gòu)造方法和setter方法。
public void save(){
userDao.insert();
}
/* @Autowired和setter方法結(jié)合
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}*/
/*@Autowired和構(gòu)造方法結(jié)合
private UserDao userDao;
public UserService(@Autowired UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}*/
}
配置文件開啟包掃描:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.dao,com.service"/>
</beans>
測試程序:
@Test
public void testAutowired(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
- 單獨(dú)使用@Autowired注解,默認(rèn)根據(jù)類型裝配【byType】。但之前也提到過,如果兩個(gè)相同類型的類在同一包下,則系統(tǒng)分辨不出自動(dòng)注解哪個(gè)bean, 例如:
兩個(gè)bean類都實(shí)現(xiàn)了UserDao接口.無法分辨
解決辦法:@Autowired注解和@Qualifier注解聯(lián)合起來才可以根據(jù)名稱進(jìn)行裝配,在@Qualifier注解中指定Bean名稱。
將Service層代碼增加一個(gè)@Qualifier注解,指定注入到userDaoForOracle:
private UserDao userDao;
@Autowired
@Qualifier("userDaoForOracle") // 這個(gè)是bean的名字。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
1.3 @Resource
- @Resource注解也可以完成非簡單類型注入, 但與@AutoWired的區(qū)別如下
- @Resource注解是JDK擴(kuò)展包中的,也就是說屬于JDK的一部分。所以該注解是標(biāo)準(zhǔn)注解,更加具有通用性。
@Autowired注解是Spring框架自己的。 - @Resource注解默認(rèn)根據(jù)名稱裝配byName,未指定name時(shí),使用屬性名作為name。通過name找不到的話會自動(dòng)啟動(dòng)通過類型byType裝配。
@Autowired注解默認(rèn)根據(jù)類型裝配byType,如果想根據(jù)名稱裝配,需要配合@Qualifier注解一起用。 - @Resource注解用在屬性上、setter方法上。
@Autowired注解用在屬性上、setter方法上、構(gòu)造方法上、構(gòu)造方法參數(shù)上。 - @Resource注解屬于JDK擴(kuò)展包,所以不在JDK當(dāng)中,需要額外引入以下依賴:【如果是JDK8的話不需要額外引入依賴。高于JDK11或低于JDK8需要引入以下依賴。】
Spring6不再支持JavaEE,它支持的是JakartaEE9。(之前所接觸的所有的 javax.* 包名統(tǒng)一修改為 jakarta.*包名了。)
若使用Spring6, 引入:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
使用:
UserDaoForOracle的名字為userDao,讓這個(gè)Bean的名字和UserService類中的UserDao屬性名一致:
package com.sunsplanter.dao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDaoForOracle")
public class UserDaoForOracle implements UserDao{
@Override
public void insert() {
System.out.println("正在向Oracle數(shù)據(jù)庫插入U(xiǎn)ser數(shù)據(jù)");
}
}
package com.sunsplanter.service;
import com.sunsplanter.dao.UserDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Resource(name = "userDaoForOracle")
private UserDao userDao;
public void save(){
userDao.insert();
}
}
測試程序:
@Test
public void testResources(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
以上代碼使用Resource注解根據(jù)name(bean id)進(jìn)行注入.Resource的的name(bean id為)userDaoForOracle,且注解寫在UserDao頭上.那么就去尋找一個(gè)名為userDaoForOracle的UserDao實(shí)現(xiàn)類進(jìn)行注入.
2 全注解開發(fā)
盡管注解開發(fā)可以省略定義bean,但只能省略自定義的bean,若引入的是外部對象(如druid),此時(shí)依然要在xml中聲明一個(gè)bean,由于此,不能完全消除配置xml文件的繁瑣。
因此引入全注解開發(fā)(基于配置類的方式管理bean)
所謂的全注解開發(fā)就是不再使用spring配置文件spring.xml了。寫一個(gè)配置類來代替配置文件. 其中配置類中使用
@configuration
@componentScan
等注解發(fā)揮spring.xml的作用
- 完全注解方式指的是去掉xml文件,使用配置類 + 注解實(shí)現(xiàn)
- xml文件替換成使用@Configuration注解標(biāo)記的類
- 標(biāo)記IoC注解:@Component,@Service,@Controller,@Repository
- 標(biāo)記DI注解:@Autowired @Qualifier @Resource @Value
- <context:component-scan標(biāo)簽指定注解范圍使用@ComponentScan(basePackages = {“com.atguigu.components”})替代
- <context:property-placeholder引入外部配置文件使用@PropertySource({“classpath:application.properties”,“classpath:jdbc.properties”})替代
- <bean 標(biāo)簽使用@Bean注解和方法實(shí)現(xiàn)
- IoC具體容器實(shí)現(xiàn)選擇AnnotationConfigApplicationContext對象
對于上例, 新增一個(gè)配置類代替spring.xml,至于Service層的代碼完全不變:
package com.sunsplanter.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
//標(biāo)注當(dāng)前類是配置類,替代spring.xml
@Configuration
//使用注解讀取外部配置,替代 <context:property-placeholder標(biāo)簽
@PropertySource("classpath:jdbc.properties")
//使用@ComponentScan注解,可以配置掃描包,替代<context:component-scan標(biāo)簽
@ComponentScan(basePackages = {"com.sunsplanter.service"})
public class Spring6Configuration {
}
@Test
public void testNoXml(){
// AnnotationConfigApplicationContext 根據(jù)配置類創(chuàng)建 IOC 容器對象
//ClassPathXmlApplicationContext根據(jù)路徑中的xml文件創(chuàng)建IOC容器對象
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class);
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
2.1 將外部類納入IoC容器管理
場景需求:將Druid連接池對象存儲到IoC容器
需求分析:如開頭所述:第三方j(luò)ar包的類,添加到ioc容器,無法使用@Component等相關(guān)注解!因?yàn)樵创ajar包內(nèi)容為只讀模式!
思路:DataSource是JavaX中的一個(gè)接口,通過實(shí)現(xiàn)該接口來獲取DataSource對象,將該方法聲明為@Bean后,用value值注入創(chuàng)建datasource所需的各種屬性。
package com.sunsplanter.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
//標(biāo)注當(dāng)前類是配置類,替代application.xml
@Configuration
//引入jdbc.properties文件
@PropertySource({"classpath:jdbc.properties"})
@ComponentScan(basePackages = {"com.sunsplanter"})
public class MyConfiguration {
//如果第三方類進(jìn)行IoC管理,無法直接使用@Component相關(guān)注解
//解決方案: xml方式可以使用<bean標(biāo)簽
//解決方案: 配置類方式,可以使用方法返回值+@Bean注解
//DataSource是JavaX中的一個(gè)接口,通過實(shí)現(xiàn)該接口來獲取DataSource對象
@Bean
public DataSource createDataSource(@Value("${jdbc.user}") String username,
@Value("${jdbc.password}")String password,
@Value("${jdbc.url}")String url,
@Value("${jdbc.driver}")String driverClassName){
//使用Java代碼實(shí)例化
//new出一個(gè)Druid連接池對象
DruidDataSource dataSource = new DruidDataSource();
//給該對象填上數(shù)據(jù)庫參數(shù)后返回,今后需要用從外部調(diào)用dataSource即可
//set方法是DataSource接口中預(yù)定義的抽象方法
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setUrl(url);
dataSource.setDriverClassName(driverClassName);
//返回結(jié)果即可
return dataSource;
}
}
2.2 @import注解
**場景1:**將外部類納入IoC管理
正常情況下,定義一個(gè)普通對象類,我們在類上聲明為@Bean,今后再編寫一個(gè)配置類configuration.java,類中配置掃描包,即可自動(dòng)尋找到所有Bean并自動(dòng)注入.
然而,一些外部類原作者編寫的時(shí)候并不可能按我們心意提前寫好@Bean注解,并且如2.1所述, 一些寫好的外部類根本不允許我們修改. 但我們卻仍想將這些外部類納入IoC容器管理.(即自動(dòng)生成對象, 自動(dòng)注入,生命周期管理…)
此時(shí)就要用到@import。
- 自定義一個(gè)類 沒有任何注解(模擬不能添加注解的外部類)
public class MyClass {
public void test() {
System.out.println("test方法");
}
}
在配置類Configuration中 import這個(gè)myClass類
@configuration
@ComponentScan(basePackages = {"com.sunsplanter"})
public class Configuration{
@Import(MyClass.class)
public class Configuration {
}
測試程序?yàn)椋?/p>
public void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Configuration.class);
//我們已經(jīng)首先根據(jù)配置類Configuration生成了上下文對象,并且在配置類我們聲明了:外部類MyClass要納入此上下文容器管理。
//因此此時(shí)可以根據(jù)這個(gè)上下文對象getBean。
MyClass myClass = applicationContext.getBean(MyClass.class);
myClass.test();
}
}
情景2:存在多個(gè)配置類,簡化生成上下文容器的流程文章來源:http://www.zghlxwxcb.cn/news/detail-794619.html
@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}
現(xiàn)在,在實(shí)例化上下文時(shí)不需要同時(shí)指定 ConfigA.class 和 ConfigB.class ,只需顯式提供 ConfigB :文章來源地址http://www.zghlxwxcb.cn/news/detail-794619.html
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
// now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
到了這里,關(guān)于11Spring IoC注解式開發(fā)(下)(負(fù)責(zé)注入的注解/全注解開發(fā))的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!