1 装配的概念
1.1 Bean 装配的概念
指在 Spring 容器中把 Bean 组装到一起,前提是容器需要知道 Bean 的依赖关系,如何通过依赖注入来把它们装配到一起。
1.2 Bean 自动装配的概念
Spring 容器可以在不使用 <constructor-arg> 和 <property> 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。
1.3 Bean 自动装配的局限性
自动装配的局限性是:
- 覆盖的可能性:仍然可以使用
<constructor-arg>和<property>设置指定依赖项,从而覆盖自动装配。 - 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String 字符串,和类。
- 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
2 基于 XML 的装配
通过 set 方法注入;通过构造器注入 (通过 index 或 type 设置参数);静态工厂注入;实例工厂注入。
2.1 属性注入
2.1.1 简单类型属性注入
<property name = "age" value = "">
该语句会调用类中的 setAge 方法,并将 value 作为参数传入进去。Name 值为 email,就调用 setEmail 方法。也可以使用注解来设置 set 方法。
需要注意,仅仅会调用 setAge 方法,对于方法内部如何实现不关心。即,set 方法不赋值,那么对应值就是 null。类中没有 email 属性,但是有 setEmail 方法,也是会调用 setEmail 方法。如果没有对应的 set 方法,那么会报错。
SetAge 方法必须只有一个参数,且 value 值可以转换成传入参数类型。
<bean id="myStudent" class="com.bjpowernode.ba01.Student" >
<property name="name" value="李四" /><!--setName("李四")-->
<property name="age" value="22" /><!--setAge(21)-->
<property name="email" value="lisi@qq.com" /><!--setEmail("lisi@qq.com")-->
</bean>2.1.2 构造器装配 Bean
<constructor-arg name="myage" value="20" />
name: 表示构造方法的形参名index: 表示构造方法的参数的位置,下标从 0 开始。Name 和 index 都不存在时,标签顺序为参数顺序。value:构造方法的形参类型是简单类型的,使用 valueref:构造方法的形参类型是引用类型的,使用 ref,属性值为其他 bean 对象的 ID,如果不存在 or 存在多个,那么将报错。
<!--使用name属性实现构造注入-->
<bean id="myStudent" class="com.bjpowernode.ba03.Student" >
<constructor-arg name="myage" value="20" />
<constructor-arg name="mySchool" ref="myXueXiao" />
<constructor-arg name="myname" value="周良"/>
</bean>
<!--使用index属性-->
<bean id="myStudent2" class="com.bjpowernode.ba03.Student">
<constructor-arg index="1" value="22" />
<constructor-arg index="0" value="李四" />
<constructor-arg index="2" ref="myXueXiao" />
</bean>
<!--省略index-->
<bean id="myStudent3" class="com.bjpowernode.ba03.Student">
<constructor-arg value="张强强" />
<constructor-arg value="22" />
<constructor-arg ref="myXueXiao" />
</bean>2.1.3 引用类型属性注入
当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。Ref 的值必须为某 bean 的 id 值。
<bean id="myStudent" class="com.bjpowernode.ba02.Student" >
<property name="name" value="李四" />
<property name="age" value="26" />
<!--引用类型-->
<property name="school" ref="mySchool" /><!--setSchool(mySchool)-->
</bean>
<!--声明School对象-->
<bean id="mySchool" class="com.bjpowernode.ba02.School">
<property name="name" value="北京大学"/>
<property name="address" value="北京的海淀区" />
</bean>另一种方式 —— 内部 Bean
<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<property name="clazz">
<!-- 在一个bean中再声明一个bean就是内部bean -->
<!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
<bean id="clazzInner" class="com.atguigu.spring6.bean.Clazz">
<property name="clazzId" value="2222"></property>
<property name="clazzName" value="远大前程班"></property>
</bean>
</property>
</bean>2.1.4 特殊值处理
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>
<!-- null值 -->
<property name="name"> <null /> </property>
<!-- 下面这种是 “null” 字符串 -->
<property name="name" value="null"></property>
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a < b"/>
<property name="expression">
<!-- 解决方案二:使用CDATA节 -->
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
</property>2.1.5 集合属性注入
public class User {
private List<GirlFriend> lists;
private Set<GirlFriend> sets;
private Map<String, GirlFriend> maps;
private Properties properties;
private String[] array;
//getter、setter、toString方法省略......
}XML 配置如下:
<ref bean=””> 和 <value >…</value> 来表示集合中的引用类型和简单类型。
<entry key="..." value-ref="..."/> 来表示 Map 中的属性
<prop key="k1">v1</prop> 来表示 Properties 中的属性
如果是 Set 的话,所有重复的值都会被忽略掉。
<bean id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<constructor-arg><null/></constructor-arg> <!--传递一个 null -->
</bean>
<!--实例化User-->
<bean id="user2" class="com.thr.pojo.User">
<!--注入List集合-->
<property name="lists">
<list>
<ref bean="girlFriend1"/>
<ref bean="girlFriend2"/>
<ref bean="girlFriend3"/>
</list>
</property>
<!--注入Set集合-->
<property name="sets">
<set>
<ref bean="girlFriend1"/>
<ref bean="girlFriend2"/>
<ref bean="girlFriend3"/>
</set>
</property>
<!--注入Map集合-->
<property name="maps">
<map>
<entry key="正牌女友" value-ref="girlFriend1"/>
<entry key="备胎1" value-ref="girlFriend2"/>
<entry key="备胎2" value-ref="girlFriend3"/>
</map>
</property>
<!--注入Properties-->
<property name="properties">
<props>
<prop key="k1">v1</prop>
<prop key="k2">v2</prop>
</props>
</property>
<!--注入数组-->
<property name="array">
<array>
<value>value1</value>
<value>value2</value>
<value>value3</value>
</array>
</property>
</bean>2.1.6 命名空间装配 Bean
2.2 属性自动注入
Spring 容器中给我们提供了完成 Bean 之间的自动装配的功能(但是只针对对象类型的自动装配),这样的好处就是有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量,因为在稍微大一点的项目中,一个被引用的 Bean 的 ID 改变了,那么需要修改所有引用了它的 ID 。Spring 框架默认是不支持自动装配的,可以使用 Spring 的配置文件中< bean >元素的 autowire 属性为一个 bean 定义指定自动装配模式。其中<bean>元素中的 autowire 属性有 5 个可选值,如下:
| 属性 | 描述 |
|---|---|
| no | 默认的设置,表示不启用自动装配,需要我们手动通过”ref”属性手动完成装配 |
| byName | 通过属性名称自动装配,如果一个 JavaBean 中的属性名称与 Bean 的 id 相同,则自动装配这个 Bean 到 JavaBean 的属性中。Spring 会查找该 JavaBean 中所有的 set 方法名,获得将 set 去掉并且首字母小写的字符串,然后去 Spring 容器中寻找是否有此字符串名称 id 的 Bean。如果有则就注入,如果没有则注入动作将不会执行 |
| byType | 通过属性类型自动装配。Spring 会在容器中查找 JavaBean 中的属性类型与 Bean 的类型一致的 Bean,并自动装配这个 Bean 到 JavaBean 的属性中,如果容器中包含多个这个类型的 Bean,Spring 将抛出异常。如果没有找到这个类型的 Bean,那么注入动作将不会执行 |
| constructor | 类似于 byType,也是通过类型自动装配,但是它是通过构造方法的参数类型来匹配。Spring 会寻找与该 JavaBean 构造方法的各个参数类型相匹配的 Bean,然后通过构造函数注入进来。如果在 Spring 容器中没有找一个构造函数参数类型的 Bean,则会报错 |
| autodetect | 表示在 constructor 和 byType 之间自动的选择注入方式 (spring 5. X 已经没有了)。首先尝试通过 constructor 来自动装配,如果它不执行,则 Spring 尝试通过 byType 来自动装配 |
| default | 由上级标签 beans 的 default-autowire 属性确定 |
引用类型属性也可以不用在配置文件中显式的注入,可以通过为 <bean> 标签设置 autowire 属性值,就可以进行隐式自动注入(默认是不自动注入引用类型属性)。
隐式自动注入分为两种:
autowire = "byName":根据名称自动注入autowire = "byType":根据类型自动注入
2.2.1 byName 方式自动注入
Java 类中 set 方法的后缀和 Spring 容器中(配置文件)<bean> 的 id 名称一样,且数据类型是一致的。
public class Student {
private String name;
// 声明一个引用类型
private School school;
// set方法的后缀与<bean>对象的id相同,因此调用setSchool2方法
public void setSchool2(School sc){}
}<bean id="myStudent" class="com.bjpowernode.ba04.Student" autowire="byName">
<property name="age" value="26" />
</bean>
<bean id="school2" class="com.bjpowernode.ba04.School">
<property name="name" value="清华大学"/>
</bean>2.2.2 byType 方式自动注入
要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即,要么相同,要么是子类 or 实现类。但是同源的被调用 bean 只能有一个。多于一个,容器就不知道匹配哪个。
public class Student {
private String name;
private int age;
//声明一个引用类型
private School school;
//private School school2;
}<!--byType-->
<bean id="myStudent" class="com.bjpowernode.ba05.Student" autowire="byType">
<property name="name" value="张飒" />
</bean>
<!--下面只能声明一种,要不只声明父类/接口,要不只声明子类/实现类-->
<!--否则student bean 会报错,提示有两种school供选择-->
<!--声明School对象-->
<bean id="mySchool" class="com.bjpowernode.ba05.School">
<property name="name" value="人民大学"/>
</bean>
<!--声明School的子类-->
<!--<bean id="primarySchool" class="com.bjpowernode.ba05.PrimarySchool">
<property name="name" value="北京小学" />
<property name="address" value="北京的大兴区" />
</bean>-->2.2.3 constructor 装配
2.2.4 default 装配
Default 装配表示由父级标签 beans 的 default-autowire 属性来配置。如果 beans 标签上设置了 default-autowire 属性,那么 default-autowire 属性会统一配置当前 beans 中的所有 bean 的自动装配方式。

- 如果子标签<bean>没有单独的设置 autowire 属性,那么将采用父标签的 default-autowire 属性的模式。
- 如果子标签<bean>单独设置了 autowire 属性,则采用自己的模式。
2.2.5 Bean 自动装配的补充
①、上述的讲到 byType 和 constructor 装配是支持数组和强类型集合(即指定了集合元素类型)。如 bean A 有个属性定义是 List<Foo>类型,Spring 会在容器中查找所有类型为 Foo 的 bean,注入到该属性。记住是 Foo,不是 List。另外如果集合是 Map 集合,那么 Map 的 key 必须是 String 类型,Spring 会根据 value 的类型去匹配。例如有属性 bean A 中有一个属性为 Map<String, Foo> p,容器中有 bean B 和 C 类型均为 Foo,那么 A 实例化完成后,p 属性的值为:{“B”:B 的实例对象,“C”:C 的实例对象}。
②、虽然 autowrie 给我们带来配置的便利性,但是也有缺点,比如会导致 bean 的关系没那么显而易见,所以用 autowire 还是 ref 还是需要根据项目来决定。
③、autowire-candidate:前面我们说到配置有 autowire 属性的 bean,Spring 在实例化这个 bean 的时候会在容器中查找匹配的 bean 对 autowire bean 进行属性注入,这些被查找的 bean 我们称为候选 bean。作为候选 bean,我凭什么就要被你用,老子不给你用。所以候选 bean 给自己增加了 autowire-candidate=“false”属性(默认是 true),那么容器就不会把这个 bean 当做候选 bean 了,即这个 bean 不会被当做自动装配对象。同样,
2.3 引入外部配置文件
2.3.1 引入 XML 配置文件
文件路径可以使用通配符 * 来匹配任意字符,从而减少类路径的个数,如下面的配置文件。但是,需要注意,总配置文件的类路径不能在通配符匹配的范围内。
<?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:c="<http://www.springframework.org/schema/c>"
xsi:schemaLocation="<http://www.springframework.org/schema/beans>
<http://www.springframework.org/schema/beans/spring-beans.xsd>">
<!-- 引入 JavaConfig -->
<bean class="soundsystem.CDConfig" />
<!-- 引入 XML -->
<import resource="cdplayer-config.xml" />
<import resource="classpath:ba06/spring-student.xml" />
<import resource="classpath:ba06/spring-*.xml" />
</beans>2.3.2 引入 properties 配置文件
jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver在 Spring 配置文件中添加 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">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>2.4 FactoryBean
35.容器:IoC-基于 XML 管理 Bean-FactoryBean_哔哩哔哩_bilibili
① 简介
FactoryBean 是 Spring 提供的一种整合第三方框架的常用机制。和普通的 bean 不同,配置一个 FactoryBean 类型的 bean,在获取 bean 的时候得到的并不是 class 属性中配置的这个类的对象,而是 getObject ()方法的返回值。通过这种机制,Spring 可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
将来我们整合 Mybatis 时,Spring 就是通过 FactoryBean 机制来帮我们创建 SqlSessionFactory 对象的。
② 创建类 UserFactoryBean
package com.atguigu.spring6.bean;
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
③ 配置 bean
<bean id="user" class="com.atguigu.spring6.bean.UserFactoryBean"></bean>④ 测试
@Test
public void testUserFactoryBean(){
//获取IOC容器
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-factorybean.xml");
User user = (User) ac.getBean("user");
System.out.println(user);
}3 基于注解的装配
3.1 使用注解创建 Bean 对象
3.1.1 @Component
- 属性 value:对象的名称 ID,唯一
//@Component(value="myStudent")
//@Component("myStudent") value 字段可以省略,直接指定 value 值
//@Component 不指定 value 属性, bean 的 id 是类名的首字母小写
public class Student { }Spring 中和 @Component 功能一致,创建对象的注解还有:
@Repository(用在持久层类的上面) : 放在 dao 的实现类上面,表示创建 dao 对象,dao 对象是能访问数据库的。@Service(用在业务层类的上面):放在 service 的实现类上面,创建 service 对象,service 对象是做业务处理,可以有事务等功能的。@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。
使用 @Component 创建对象后,还需要增加组件扫描来放到 Spring 容器中。当前有两种方案:
- 在配置文件中增加组件扫描器,扫描哪里使用了 @Component 注解。
- 扫描组件注解 @ComponentScan - @ComponentScan
3.1.2 组件扫描器
在配置文件中增加组件扫描器,扫描哪里使用了 @Component 注解。
另外参考 @ComponentScan 关于 filter 等其他属性配置。
- 多组组件扫描器,扫描不同的包
- 使用分隔符 (
;或,或空格(不推荐)) 分割多个包名 - 指定父包,但是会使得扫描包数目增加,启动时间变慢
<!--指定多个包的三种方式-->
<!--第一种方式:使用多次组件扫描器,指定不同的包-->
<context:component-scan base-package="com.bjpowernode.ba01"/>
<context:component-scan base-package="com.bjpowernode.ba02"/>
<!--第二种方式:使用分隔符 ; 或 , 分隔多个包名-->
<context:component-scan base-package="com.bjpowernode.ba01;com.bjpowernode.ba02" />
<!--第三种方式:指定父包-->
<context:component-scan base-package="com.bjpowernode" />3.1.3 扫描组件注解
(通过这种方法可以实现 Spring 全注解开发,不用再写 Spring 配置文件)
在任意一个类上添加 @ComponentScan 注解即可,这里用一个新建的 JavaConfig 来告诉 Spring 容器怎么扫描,就是指定扫描哪个包。
package com.thr.pojo;
import org.springframework.context.annotation.ComponentScan;
@Configuration
@ComponentScan
public class PojoConfig { }@ComponentScan 注解如果不指定扫描哪个包的话,默认是扫描当前类的包路径 (这里是 com. Thr. Pojo),将当前包下的所有被 @Component 注解的 Bean 对象加入到 Spring 容器。
@ComponentScan 两个属性配置项 basePackages 和 basePackageClasses :
- Value:等价于 basePackages。
- BasePackages:表示扫描的包路径,单个路径用 String,多个路径用 String 数组?。
- BasePackageClasses:表示扫描的类,也可以配置多个。
通过上述配置项来扫描其他包路径下的 Bean 对象。
package com.thr.config;
import org.springframework.context.annotation.ComponentScan;
@Configuration
//@ComponentScan(basePackages = "com.thr.pojo")
//@ComponentScan(basePackages={"soundsystem", "video"})
//@ComponentScan(basePackageClasses =User.class)
@ComponentScan(basePackages = "com.thr.pojo",basePackageClasses = User.class)
public class PojoConfig { }3.2 属性注入
简单类型属性通过 @Value 注解进行注入。
@Value("..")
简单类型的属性赋值。可以在属性定义上面,也可以在 set 方法上面。Value 值为要注入的值。标记在属性上时,setter 方法可以省略。
下述方法中,先创建 Student 对象。创建对象时,读取配置文件中的 myname 和 myage 数据并赋值。之后,调用 setAge 方法,传入注解中提供的 value 值。即,最后 age 为 30.
@Component("myStudent")
public class Student {
//@Value("李四")
@Value("${myname}") //使用属性配置文件中的数据
private String name;
@Value("${myage}") //使用属性配置文件中的数据
private Integer age;
@Value("30")
public void setAge(Integer age) {
System.out.println("setAge:"+age);
this.age = age;
}
}Spring 配置文件
<!--添加组件扫描器-->
<context:component-scan base-package="com.bjpowernode.ba02" />
<!--加载属性配置文件-->
<context:property-placeholder location="classpath:test.properties" />3.3 属性自动注入
3.3.1 @Autowired 自动注入
在构造器方法、Setter 方法上增加 @Autowired 注解,那么 Spring 就可以从容器中自动搜索并装配到对应位置。注解也可以直接配置到引用类型属性上,但是官方并不推荐。
@Autowired 注解代码:
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}注解可以使用的位置:构造方法上、方法上、形参上、属性上、注解上。
@Service
public class UserServiceImpl implements UserService {
// 构造器注入
@Autowired
public UserServiceImpl(UserDao userDao) { this.userDao = userDao; }
// 形参注入
public UserServiceImpl(@Autowired UserDao userDao) { this.userDao = userDao; }
// 属性注入
@Autowired
private UserDao userDao;
// set 注入
@Autowired
public void setUserDao(UserDao userDao) { this.userDao = userDao; }@Autowired 还有一个属性 required,默认值为 true,表示当自动装配失败后,会终止程序运行。设置为 false,自动装配失败后,对应属性为 null。
使用 @Autowired 注解来自动装配指定的 Bean。在使用@Autowired 注解之前需要在 Spring 配置文件进行配置,<context:annotation-config />。
在启动 spring IoC 时,容器自动装载了一个 AutowiredAnnotationBeanPostProcessor 后置处理器,当容器扫描到@Autowied、@Resource 或@Inject 时,就会在 IoC 容器自动查找需要的 Bean,并装配给该对象的属性。在使用@Autowired 时,首先在容器中查询对应类型的 Bean:
- 如果查询结果刚好为一个,就将该 Bean 装配给@Autowired 指定的数据;
- 如果查询的结果不止一个,那么@Autowired 会根据名称来查找;
- 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用 required=false。
与 @Qualifier 注解配合,按照 byName 装配:
@Autowired(required = false)
@Qualifier("mySchool")
private School school;疑问:
Spring 什么时候去根据 @Autowired 注解寻找 Bean 对象的依赖?
怎么去找 Bean 的依赖呢,查看所有 @Autowired 注解修饰的方法或字段?
会不会存在冲突呢,如下面同时有构造器+Setter 注入?
如果有多个 Setter 注入呢?有没有顺序呢?
3.3.2 JDK 注解 @Resource 自动注入
@Resource 注解也可以完成属性注入。
@Autowired 和@Resource 都可用于:属性上、setter 方法上,都可以用来装配 bean。
@Autowired 和@Resource 之间的区别
一是,@Autowired 默认按类型装配,属于 Spring 注解;@Resource 默认按照名称装配,属于 Java 注解。
二是,@Autowired 默认按类型装配;实现按名称装配需要@Autowired + @Qualifier 注解;默认对象必须存在,若可以为 null,required 属性为 false。
三是,@Resource 根据 name 和 type 属性的有无,四种不同的装配方式。
@Resource 注解属于 JDK 扩展包,所以不在 JDK 当中,需要额外引入以下依赖:【如果是 JDK 8 的话不需要额外引入依赖。高于 JDK 11 或低于 JDK 8 需要引入以下依赖。】补充:JDK 11 将 javax. Annotation 这个包移除了,如果想继续使用可以通过 maven 或者其他方式导入。
<dependency>
<groupId>jakarta. Annotation</groupId>
<artifactId>jakarta. Annotation-api</artifactId>
<version>2.1.1</version>
</dependency>@Resource 注解:默认 byName 注入,没有指定 name 时把属性名当做 name,根据 name 找不到时,才会 byType 注入。ByType 注入时,某种类型的 Bean 只能有一个。
使用范例:
@Service
Public class UserServiceImpl implements UserService {
// 指定 name
@Resource (name = "myUserDao")
Private UserDao myUserDao;
// 根据属性名作为 name
@Resource
Private UserDao myUserDao;
}4 基于 Java 类的装配
如果要使用外部包的 Java 对象,将其简单修改后注入到 Spring 容器时,自动化装配就无法使用。此时,推荐采用 Java 代码装配 Bean 对象,涉及到 @Configuration 与 @Bean 注解。
又或者是,想要创建同一个类型的不同属性的 Java Bean,也可以使用这种方法来完成。
4.1 @Configuration 与 @Bean 介绍
@Configuration :标注在类上,作用:配置 Spring 容器 (应用上下文),被它修饰的类表示可以使用 Spring IoC 容器作为 bean 定义的来源。
@Bean :标注在方法上,作用:注册 bean 对象,被标记的方法的返回值会作为 bean 被加入到 Spring IoC 容器之中,bean 的名称默认为方法名。@Bean 的配置项中包含 5 个配置项:
- Value:等同于下面的 name 属性
- Name:相当于 bean 的 id,它是一个字符串数组,允许配置多个 BeanName
- autowire:标志是否是一个引用的 Bean 对象,默认值是 Autowire.NO
- InitMethod:自定义初始化方法
- DestroyMethod:自定义销毁方法
4.2 @Configuration 与 @Bean 举例
Java 代码装配 Bean 使用示例如下:
@ComponentScan (basePackages = "com. Thr. Pojo")
@Configuration
Public class PojoConfig {
Public PojoConfig () { System. Out. Println ("PojoConfig 容器初始化成功..."); }
//实例化 User 对象并且装配值
@Bean (name = "user")
Public User user (){
User user = new User ();
User. SetUserId (2021);
User. SetUserName ("菜逼小唐");
Return user;
}
//实例化 GirlFriend 对象并且装配值
@Bean (name ="girlFriend" )
Public GirlFriend girlFriend (){
GirlFriend girlFriend = new GirlFriend ();
GirlFriend. SetGirlName ("陈美丽");
Return girlFriend;
}
//实例化 GirlFriend 对象,创建同类不同属性的对象
@Bean (name ="girlFriend 1" )
Public GirlFriend girlFriend 1 (){
GirlFriend girlFriend 1 = new GirlFriend ();
GirlFriend 1. SetGirlName ("何美丽");
Return girlFriend 1;
}
// 方法可以是有参方法,此时 Spring 会自动寻找对象注入到方法的入参中
@Bean
Public CDPlayer cdPlayer (CompactDisc compactDisc) {
Return new CDPlayer (compactDisc);
}
}
如果要获取它们,我们可以使用 AnnotationConfigApplicationContext 或 AnnotationConfigWebApplicationContext 类进行扫描,并用于构建 bean 定义,初始化 Spring 容器。
Public class SpringTest 1 {
Public static void main (String[] args) {
//1. 初始化 Spring 容器,通过注解加载
ApplicationContext applicationContext = new AnnotationConfigApplicationContext (PojoConfig. Class);
//2. 通过容器获取实例
User user = applicationContext. GetBean ("user", User. Class);
//3. 调用实例中的属性
System. Out. Println (user. GetUserId ()+"----"+
User. GetUserName ()+"----"+
User. GetUserAge ()+"----"+
User. GetGirlFriend ());
}
}4.3 @Component 和 @Bean 的区别是什么?
- @Component 注解作用于类,而 @Bean 注解作用于方法。
- @Component 通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 Bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 Bean, @Bean 告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我。
- @Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 Bean。比如当我们引用第三方库中的类需要装配到 Spring 容器时,则只能通过 @Bean 来实现
4.4 @import 注解
4.5 JavaConfig 导入 JavaConfig/XML 配置
JavaConfig 导入 JavaConfig 配置
PojoConfig 类中导入 GirlFriendConfig 配置,也可以如 CDPlayerConfig 一次导入多个配置。
@Configuration
Public class GirlFriendConfig{...}
@ComponentScan (basePackages = "com. Thr. Pojo")
@Configuration
@Import (GirlFriendConfig. Class)
Pubiic class PojoConfig {...}
@Configuration
@Import ({CDPlayerConfig. Class, CDConfig. Class})
Public class CDPlayerConfig {...}JavaConfig 导入 XML 配置
假设 BlankDisc 定义在名为 cdconfig. Xml 的文件中,该文件位于根类路径下,那么可以修改 SoundSystemConfig,让它使用 @ImportResource 注解,如下所示:
Package soundsystem;
Import org. Springframework. Context. Annotation. Configuration;
Import org. Springframework. Context. Annotation. Import;
Import org. Springframework. Context. Annotation. ImportResource;
@Configuration
@Import (CDPlayerConfig. Class)
@ImportResource ("classpath: ")
Public class SoundSystemConfig { ... }