Spring Bean属性注入的 N 种方式
日积月累,水滴石穿 😄
前言
Bean 属性注入,就是将属性注入到 Bean 中的过程,而这属性可以普通属性,也可以是一个对象(Bean)。
Spring 实现属性注入的方式有两种:
- 构造函数注入
- set方法注入
但是具体的操作方式也分为两种:
- 基于 xml 配置文件方式实现
- 基于注解方式实现
我们先来使用 xml 配置文件操作 set方法注入、构造函数注入属性,
加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.17</version>
</dependency>
<!--用于测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
加入 context 依赖,一个依赖就包含了 aop、beans、core、expression。
xml 配置文件
构造函数注入
1、 创建一个名为 User2 的类,定义属性和对应的有参构造方法,代码如下。
public class User2 {
//普通属性
private String name;
private String address;
//对象属性
private Card card;
public User2(String name, String address, Card card) {
this.name = name;
this.address = address;
this.card = card;
}
@Override
public String toString() {
return "User2{" +
"name='" + name + ''' +
", address='" + address + ''' +
", card=" + card +
'}';
}
}
- 2、再创建一个名为 Card 类的对象,定义属性和对应的有参构造方法,代码如下。
public class Card {
private String cardId;
private String cardName;
public Card(String cardId, String cardName) {
this.cardId = cardId;
this.cardName = cardName;
}
@Override
public String toString() {
return "Card{" +
"cardId='" + cardId + ''' +
", cardName='" + cardName + ''' +
'}';
}
}
- 3、在 resources 目录下创建 Spring 配置文件 IOC02.xml,配置如下。
<bean id="user02" class="com.cxyxj.dto.User2">
<constructor-arg name="name" value="cxyxj"></constructor-arg>
<constructor-arg name="address" value="shs"></constructor-arg>
<constructor-arg name="card" ref="card"></constructor-arg>
</bean>
<bean id="card" class="com.cxyxj.dto.Card">
<constructor-arg index="0" value="1222"></constructor-arg>
<constructor-arg index="1" value="zsyh"></constructor-arg>
</bean>
上面使用 constructor-arg 标签完成了属性的注入。 name:类的属性名称, value:需要向属性注入的值,index:参数所属下标,ref:创建 card 对象 bean 标签的 id 值。Bean 的构造函数内有多少参数,就需要使用多少个 元素。
- 测试。
@Test
public void test2(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC02.xml");
// 获取配置创建的对象
User2 user = context.getBean("user02", User2.class);
System.out.println(user);
}
结果如下:
User2{name='cxyxj', address='shs', card=Card{cardId='1222', cardName='zsyh'}}
set方法注入
在 Spring 实例化 Bean 的过程中,IoC 容器首先会调用无参构造方法,实例化 Java 对象,然后通过 反射机制调用这个 Bean 的 setXxx() 方法,将属性值注入到 Bean 中。
- 1、修改 User2 类的代码,代码如下:
public class User2 {
private String name;
private String address;
private Card card;
public User2() {
System.out.println("User2 构造方法执行");
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public void setCard(Card card) {
this.card = card;
}
@Override
public String toString() {
return "User2{" +
"name='" + name + ''' +
", address='" + address + ''' +
", card=" + card +
'}';
}
}
- 2、修改 Card 类的代码,代码如下:
public class Card {
private String cardId;
private String cardName;
public Card() {
System.out.println("Card 构造方法执行");
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public void setCardName(String cardName) {
this.cardName = cardName;
}
@Override
public String toString() {
return "Card{" +
"cardId='" + cardId + ''' +
", cardName='" + cardName + ''' +
'}';
}
}
- 修改 spring 配置文件,代码如下:
<bean id="user02" class="com.cxyxj.dto.User2">
<property name="name" value="cxyxj"></property>
<property name="address" value="shs"></property>
<property name="card" ref="card"></property>
</bean>
<bean id="card" class="com.cxyxj.dto.Card">
<property name="cardId" value="2222"></property>
<property name="cardName" value="zsyh"></property>
</bean>
上面使用 property 标签完成了属性的注入。 name:类的属性名称, value:需要向属性注入的值,ref:创建 card 对象 bean 标签的 id 值。
- 测试。
@Test
public void test2(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC02.xml");
// 获取配置创建的对象
User2 user = context.getBean("user02", User2.class);
System.out.println(user);
user.test2();
}
结果如下:
User2 构造方法执行
Card 构造方法执行
User2{name='cxyxj', address='shs', card=Card{cardId='2222', cardName='zsyh'}}
短命名空间注入
我们在通过构造函数或 set 方法进行属性注入时,通常是在 元素中嵌套 和 元素来实现的。这种方式虽然结构清晰,但书写较繁琐。
Spring 框架提供了 2 种短命名空间,可以简化基于 xml 配置方式,如下。
p 命名空间注入
p 命名空间注入,可以简化 set 方法方式属性注入。
- 1、添加 p 命名空间XML 约束
xmlns:p="http://www.springframework.org/schema/p"
- 2、导入之后,进行属性注入,在 bean 标签里面进行操作。
<bean id="user02" class="com.cxyxj.dto.User2" p:name="cxyxj" p:address="shs" p:card-ref="card">
</bean>
<bean id="card" class="com.cxyxj.dto.Card" p:cardId="3333" p:cardName="zsyh">
</bean>
p:普通属性="普通属性值",p:对象属性-ref="对象的引用"。
- 测试
@Test
public void test2(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC02.xml");
// 获取配置创建的对象
User2 user = context.getBean("user02", User2.class);
System.out.println(user);
user.test2();
}
结果如下:
User2 构造方法执行
Card 构造方法执行
User2{name='cxyxj', address='shs', card=Card{cardId='3333', cardName='zsyh'}}
c 命名空间注入
c 命名空间注入,可以简化构造方法方式属性注入。
将代码还原成构造函数注入时的代码,其实就是需要构造方法。
- 1、添加 c 命名空间XML 约束
xmlns:c="http://www.springframework.org/schema/c"
- 2、导入之后,进行属性注入,在 bean 标签里面进行操作。
<bean id="user02" class="com.cxyxj.dto.User2" c:name="cxyxj" c:address="shs" c:card-ref="card">
</bean>
<bean id="card" class="com.cxyxj.dto.Card" c:_0="4444" c:_1="zsyh">
c:普通属性="普通属性值",c:对象属性-ref="对象的引用",c:_下标值="普通属性值", c:_下标值-ref="对象的引用"
定义内部 Bean
上述例子创建的Bean是外部Bean,那如何创建内部Bean呢?我们将定义在 元素的 或 元素内部的 Bean,称为内部 Bean。这里就拿 标签举例。
- 1、对象复用之前的,修改配置文件内容,如下
<bean id="user02" class="com.cxyxj.dto.User2">
<property name="name" value="cxyxj"></property>
<property name="address" value="shs"></property>
<property name="card">
<bean class="com.cxyxj.dto.Card">
<property name="cardId" value="5555"></property>
<property name="cardName" value="内部Bean"></property>
</bean>
</property>
</bean>
注意:内部 Bean 是匿名的,不需要指定 id,即使指定也不会被Spring 容器作为Bean的唯一标识。内部Bean随着外部 Bean 创建而创建,内部 Bean 无法被注入到它所在的 Bean 以外的其他 Bean 中。
- 测试
@Test
public void test2(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC02.xml");
// 获取配置创建的对象
User2 user = context.getBean("user02", User2.class);
System.out.println(user);
user.test2();
}
结果如下:
User2 构造方法执行
Card 构造方法执行
User2{name='cxyxj', address='shs', card=Card{cardId='5555', cardName='内部Bean'}}
其他类型的注入
上面演示了普通类型和对象类型的注入,但是还有其他类型也是常用的。比如数组、List、Map、Set。
- 1、创建名为 Demo 的类,定义数组、list、map、set 类型属性并生成对应 的set 方法。
public class Demo {
// 数组
private String[] courses;
//list 集合
private List<String> list;
// map 集合
private Map<String, String> maps;
// set 集合
private Set<String> sets;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
@Override
public String toString() {
return "Demo{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", maps=" + maps +
", sets=" + sets +
'}';
}
}
- 2、创建 IOC03.xml 配置文件并进行配置
<bean id="demo" class="com.cxyxj.dto.Demo">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>courses-1</value>
<value>courses-2</value>
</array>
</property>
<property name="list">
<list>
<ref bean="card"></ref>
<ref bean="card"></ref>
</list>
</property>
<property name="maps">
<map>
<entry key="maps-1" value-ref="card"></entry>
<entry key="maps-2" value-ref="card"></entry>
</map>
</property>
<property name="sets">
<set>
<value>sets-1</value>
<value>sets-2</value>
</set>
</property>
</bean>
<bean id="card" class="com.cxyxj.dto.Card">
<property name="cardId" value="2222"></property>
<property name="cardName" value="zsyh"></property>
</bean>
- 3、测试
@Test
public void test3(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC03.xml");
// 获取配置创建的对象
Demo info = context.getBean("demo", Demo.class);
System.out.println(info);
}
结果如下:
Card 构造方法执行
Demo{courses=[courses-1, courses-2], list=[Card{cardId='2222', cardName='zsyh'}, Card{cardId='2222', cardName='zsyh'}], maps={maps-1=Card{cardId='2222', cardName='zsyh'}, maps-2=Card{cardId='2222', cardName='zsyh'}}, sets=[sets-1, sets-2]}
写法并没有很大的出入,对应的类型会有对应的标签。
公用配置抽取
- 1、引入命名空间 util
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
- 2、拿 list 举例,对其进行抽取
<util:list id="list">
<ref bean="card"></ref>
<ref bean="card"></ref>
</util:list>
- 3、进行引用,使用 ref 指向 util:list 标签的id。
<property name="list" ref="list"></property>
- 测试
@Test
public void test3(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC03.xml");
// 获取配置创建的对象
Demo info = context.getBean("demo", Demo.class);
System.out.println(info);
}
结果如下:
Card 构造方法执行
Demo{courses=[courses-1, courses-2], list=[Card{cardId='2222', cardName='zsyh'}, Card{cardId='2222', cardName='zsyh'}], maps={maps-1=Card{cardId='2222', cardName='zsyh'}, maps-2=Card{cardId='2222', cardName='zsyh'}}, sets=[sets-1, sets-2]}
xml自动装配
前面在进行Bean 与 Bean之间属性注入的时候,我们需要在配置文件中使用 property 标签或者 constructor-arg 中的 ref 属性手动维护依赖关系才能正确的进行属性注入。随着容器中 Bean 的增多,我们的XML 配置也越来越复杂,越与难以维护。为了解决这一问题,Spring 框架为我们提供了自动装配功能。
什么是自动装配
根据指定的装配规则(一共有五种),Spring 将自动匹配,然后将属性值进行注入。
自动装配规则
属性值 | 说明 |
---|---|
byName | 按名称自动装配。 Spring 会根据的 Java 类中对象属性的名称,在整个IoC 容器中查找。如果某个 Bean 的 id 或 name 属性值与这个对象属性的名称相同,则获取这个 Bean,赋值给当前的 Java 类中对象属性。 |
byType | 按类型自动装配。 Spring 会根据 Java 类中的对象属性的类型,在整个IoC 容器中查找。若某个 Bean 的 class 属性值与这个对象属性的类型相匹配,则获取这个 Bean,赋值给当前的 Java 类中对象属性。 |
constructor | 类似于构造函数参数的“byType”,如果在容器中没有找到与构造器参数类型一致的 Bean,那么将抛出异常。 |
default | 表示默认采用上一级元素 设置的自动装配规则(default-autowire)进行装配。 |
no | 默认值,表示不使用自动装配,Bean 引用必须通过 <constructor-arg> 和 <property> 元素的 ref 属性来定义。 |
接下来分别介绍每种装配规则的使用方式。
使用
准备工作
- 1、创建名为 Order 的类,定义属性并生成对应的 set 方法、构造方法。
public class Order {
private String name;
private String address;
private Product product;
public Order(String name, String address, Product product) {
System.out.println("Order 有参构造方法执行");
this.name = name;
this.address = address;
this.product = product;
}
public Order() {
System.out.println("Order 无参构造方法执行");
}
public void setName(String name) {
System.out.println("setName 方法执行");
this.name = name;
}
public void setAddress(String address) {
System.out.println("setAddress 方法执行");
this.address = address;
}
public void setProduct(Product product) {
System.out.println("setProduct 方法执行");
this.product = product;
}
@Override
public String toString() {
return "Order{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", product=" + product +
'}';
}
}
- 2、创建名为 Product 的类,定义属性并生成对应的 set 方法、构造方法。
public class Product {
private String productId;
private String productName;
public Product() {
System.out.println("Product 无参构造方法执行");
}
public Product(String productId, String productName) {
System.out.println("Product 有参构造方法执行 ===》");
this.productId = productId;
this.productName = productName;
}
public void setProductId(String productId) {
System.out.println("setProductId 方法执行 ===》");
this.productId = productId;
}
public void setProductName(String productName) {
System.out.println("setProductName 方法执行 ===》");
this.productName = productName;
}
@Override
public String toString() {
return "Product{" +
"productId='" + productId + '\'' +
", productName='" + productName + '\'' +
'}';
}
}
- 3、编写测试方法逻辑
@Test
public void test4(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC04.xml");
// 获取配置创建的对象
Order info = context.getBean("order", Order.class);
System.out.println(info);
}
no规则使用
默认值,表示不使用自动装配。配置文件内容如下:
<bean id="order" class="com.cxyxj.dto.autowire.Order" autowire="no">
<property name="name" value="生发水订单"></property>
<property name="address" value="shs"></property>
<property name="product" ref="product"></property>
</bean>
<bean id="product" class="com.cxyxj.dto.autowire.Product">
<property name="productId" value="123456"></property>
<property name="productName" value="生发水"></property>
</bean>
执行 test4() 方法,控制台输出如下:
Order 无参构造方法执行
Product 无参构造方法执行
setProductId 方法执行 ===》
setProductName 方法执行 ===》
setName 方法执行
setAddress 方法执行
setProduct 方法执行
Order{name='生发水订单', address='shs', product=Product{productId='123456', productName='生发水'}}
byName
根据属性名称自动注入,XML 文件中 Bean 的 id 或 name 必须与类中的属性名称相同。配置文件内容如下:
<bean id="order" class="com.cxyxj.dto.autowire.Order" autowire="byName">
<property name="name" value="生发水订单"></property>
<property name="address" value="shs"></property>
<!-- <property name="product" ref="product"></property>-->
</bean>
<bean id="product" class="com.cxyxj.dto.autowire.Product">
<property name="productId" value="123456"></property>
<property name="productName" value="生发水"></property>
</bean>
执行 test4() 方法,控制台输出如下:
Order 无参构造方法执行
Product 无参构造方法执行
setProductId 方法执行 ===》
setProductName 方法执行 ===》
setName 方法执行
setAddress 方法执行
setProduct 方法执行
Order{name='生发水订单', address='shs', product=Product{productId='123456', productName='生发水'}}
测试一下 Bean的id与类中的属性名称不一致的情况,将 product 修改为 product1,配置文件内容如下:
<bean id="order" class="com.cxyxj.dto.autowire.Order" autowire="byName">
<property name="name" value="生发水订单"></property>
<property name="address" value="shs"></property>
<!-- <property name="product" ref="product"></property>-->
</bean>
<bean id="product1" class="com.cxyxj.dto.autowire.Product">
<property name="productId" value="123456"></property>
<property name="productName" value="生发水"></property>
</bean>
执行 test4() 方法,控制台输出如下:
Order 无参构造方法执行
setName 方法执行
setAddress 方法执行
Product 无参构造方法执行
setProductId 方法执行 ===》
setProductName 方法执行 ===》
Order{name='生发水订单', address='shs', product=null}
byType
据属性类型注入,即使 XML 文件中 Bean 的 id 或 name 与类中的属性名不同,只要 Bean 的 class 属性值与类中的对象属性的类型相同,就可以完成自动装配。配置文件内容如下:
<bean id="order" class="com.cxyxj.dto.autowire.Order" autowire="byType">
<property name="name" value="生发水订单"></property>
<property name="address" value="shs"></property>
<!-- <property name="product" ref="product"></property>-->
</bean>
<bean id="product1" class="com.cxyxj.dto.autowire.Product">
<property name="productId" value="123456"></property>
<property name="productName" value="生发水"></property>
</bean>
执行 test4() 方法,控制台输出如下:
Order 无参构造方法执行
Product 无参构造方法执行
setProductId 方法执行 ===》
setProductName 方法执行 ===》
setName 方法执行
setAddress 方法执行
setProduct 方法执行
Order{name='生发水订单', address='shs', product=Product{productId='123456', productName='生发水'}}
但如果同时存在多个相同类型的 Bean,则会自动注入失败,并且抛出异常。配置文件内容如下:
<bean id="order" class="com.cxyxj.dto.autowire.Order" autowire="byType">
<property name="name" value="生发水订单"></property>
<property name="address" value="shs"></property>
<!-- <property name="product" ref="product"></property>-->
</bean>
<bean id="product1" class="com.cxyxj.dto.autowire.Product">
<property name="productId" value="123456"></property>
<property name="productName" value="生发水"></property>
</bean>
<bean id="product2" class="com.cxyxj.dto.autowire.Product">
<property name="productId" value="123456"></property>
<property name="productName" value="生发水"></property>
</bean>
执行 test4() 方法,控制台输出如下:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error
creating bean with name 'order' defined in class path resource
[IOC04.xml]: Unsatisfied dependency expressed through bean property
'product'; nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.cxyxj.dto.autowire.Product' available:
expected single matching bean but found 2: product1,product2
根据类型找到了多个Bean,分别是 product1、product2。
constructor
根据构造函数进行自动装配。property 标签 修改为 constructor-arg 标签。配置文件内容如下:
<bean id="order" class="com.cxyxj.dto.autowire.Order" autowire="constructor">
<constructor-arg name="name" value="生发水订单"></constructor-arg>
<constructor-arg name="address" value="shs"></constructor-arg>
</bean>
<bean id="product1" class="com.cxyxj.dto.autowire.Product">
<constructor-arg name="productId" value="123456"></constructor-arg>
<constructor-arg name="productName" value="生发水"></constructor-arg>
</bean>
执行 test4() 方法,控制台输出如下:
Product 有参构造方法执行 ===》
Order 有参构造方法执行
Order{name='生发水订单', address='shs', product=Product{productId='123456', productName='生发水'}}
default
采用上一级标签 设置的装配规则(default-autowire)进行装配,配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="constructor">
<bean id="order" class="com.cxyxj.dto.autowire.Order">
<constructor-arg name="name" value="生发水订单"></constructor-arg>
<constructor-arg name="address" value="shs"></constructor-arg>
</bean>
<bean id="product1" class="com.cxyxj.dto.autowire.Product">
<constructor-arg name="productId" value="123456"></constructor-arg>
<constructor-arg name="productName" value="生发水"></constructor-arg>
</bean>
</beans>
执行 test4() 方法,控制台输出如下:
Product 有参构造方法执行 ===》
Order 有参构造方法执行
Order{name='生发水订单', address='shs', product=Product{productId='123456', productName='生发水'}}
注解方式
我们可以使用注解来实现自动装配,再次简化 Spring 的 XML 配置。
定义 Bean 的注解
Spring 对定义 Bean 提供了四个注解,如下:
注解 | 说明 |
---|---|
@Component | 该注解可以作用在应用的任何层次,例如 Service 层、Dao 层等。将标注的类注册为 Spring 中的 Bean。 |
@Repository | 该注解用于数据访问层(Dao 层),将标注的类注册为 Spring 中的 Bean。 |
@Service | 该注解用于业务层(Service 层),将标注的类注册为 Spring 中的 Bean。 |
@Controller | 该注解用在于控制层(web层),将标注的类注册为 Spring 中的 Bean。 |
上面四个注解功能是一样的,都可以直接标注在 Java 类上,使它们成为 Spring Bean 实例
实现属性注入的注解
可以通过以下注解将定义好 Bean 装配到其它的 Bean 中。
注解 | 说明 |
---|---|
@Autowired | 可以在 Bean 的属性变量、setter 方法、非 setter 方法及构造函数上使用,默认按照 Bean 的类型进行装配,如果匹配到多个类型则名称再次匹配。如果想指定名称(byName)来装配,可以结合 @Qualifier 注解一起使用。 |
@Qualifier | 与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。 |
@Resource | 是javax 的注解,作用与 Autowired 相同,区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 的名称进行装配。 @Resource 中有两个重要属性:name 和 type。Spring 将 name 属性解析为 Bean 的实例名称,type 属性解析为 Bean 的实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配;如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。 |
引入依赖
我们导入的依赖中已经包含了注解的运行环境(spring-aop),所以不需要再次进行导入。
开启组件扫描
Spring 默认是不使用注解进行装配Bean的,因此我们需要在 Spring 的 XML 配置文件中,通过 <context:component-scan>
标签开启 Spring 的组件扫描功能。开启后,Spring 会自动扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。
- 1、加入 context 命名空间
<?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">
</beans>
- 2、开启组件扫描
<!--开启组件扫描-->
<context:component-scan base-package="com.cxyxj"></context:component-scan>
如果需要扫描多个包,多个包使用逗号隔开
注入方式
@Autowired
- 3、在项目中创建新包 dao,在其中创建名为 UserService 的类。
package com.cxyxj.dao;
public interface UserDao {
void insertUser();
}
创建名为 UserDaoImpl 的子类,如下:
package com.cxyxj.dao;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Repository(value = "userDaoImpl")
public class UserDaoImpl implements UserDao {
@Override
public void insertUser() {
System.out.println("UserDaoImpl insertUser 执行 ====》");
}
}
UserDaoImpl 类上被 @Repository 标注。相当于 xml 配置 <bean id="userDaoImpl"class="com.cxyxj.dao.UserDaoImpl">
。
注解里面 value 属性值可以省略不写,默认值是类名称首字母小写。
- 4、在项目中创建新包 service,在其中创建名为 UserService 的类。
package com.cxyxj.service;
import com.cxyxj.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void testInsert(){
userDao.insertUser();
}
}
UserService 类上被 @Service 标注,其中 UserDao 属性被 @Autowired 标注。
- 5、编写测试方法逻辑并执行
@Test
public void test5(){
// 加载 spring 配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("IOC05.xml");
// 获取配置创建的对象
UserService info = context.getBean("userService", UserService.class);
info.testInsert();
}
结果如下:
UserDaoImpl insertUser 执行 ====》
多个类型注入
给 UserDao 新增一个子类 UserDaoImpl2。
package com.cxyxj.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl2 implements UserDao{
@Override
public void insertUser() {
System.out.println("UserDaoImpl2 insertUser 执行 ====》");
}
}
运行test5方法,会抛出异常。根据类型找到了多个Bean,分别是 userDaoImpl,userDaoImpl2。上面说过如果匹配到多个类型则名称再次匹配,所以我们修改代码如下:
@Service
public class UserService {
@Autowired
private UserDao userDaoImpl2;
public void testInsert(){
userDaoImpl2.insertUser();
}
}
执行 test5() 方法,控制台输出如下:
UserDaoImpl2 insertUser 执行 ====》
@Qualifier
也可以由 Qualifier 注解指定 bean 的名称进行注入。代码如下:
@Service
public class UserService {
@Autowired
@Qualifier(value = "userDaoImpl")
private UserDao userDao;
public void testInsert(){
userDao.insertUser();
}
}
执行 test5() 方法,控制台输出如下:
UserDaoImpl insertUser 执行 ====》
@Resource
@Service
public class UserService {
@Resource(name = "userDaoImpl2")
private UserDao userDao;
public void testInsert(){
userDao.insertUser();
}
}
执行 test5() 方法,控制台输出如下:
UserDaoImpl2 insertUser 执行 ====》
纯注解开发
- 1、创建类,替代 xml 配置文件
@ComponentScan(basePackages = "com.cxyxj")
public class SpringMain {
}
- 2、使用 AnnotationConfigApplicationContext 容器加载
@Test
public void test6(){
// 加载 spring 配置文件
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringMain.class);
// 获取配置创建的对象
UserService info = context.getBean("userService", UserService.class);
info.testInsert();
}
结果如下:
UserDaoImpl2 insertUser 执行 ====》
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。
转载自:https://juejin.cn/post/7087819601651695653