7、Bean的自动装配
自动装配是 Spring 满足 bean 依赖的一种方式!
Spring 会在上下文中自动寻找,并自动给bean 装配属性!
在Spring中有三种装配方式
- 在 xml 中显示配置
- 在 java 中显示配置
- 隐式的自动装配bean
7.1、测试
1.环境搭建
- 一个人 有两个宠物!
7.2、ByName 自动装配
会自动在容器上下文中查找,和自己对象 set 方法后面的值相对应的beanid。需要保证beanID是唯一的
<bean id="cat" class="com.lsw.pojo.Cat"/>
<bean id="dog" class="com.lsw.pojo.Dog"/>
<bean id="person" class="com.lsw.pojo.Person" autowire="byName">
<property name="name" value="时倾"/>
</bean>
7.3、ByType自动装配
会自动在容器上下文中查找,和自己对象属性类型相同的bean!id 可以省略了~但是 必须唯一
<bean class="com.lsw.pojo.Cat"/>
<bean class="com.lsw.pojo.Dog"/>
<bean id="person" class="com.lsw.pojo.Person" autowire="byType">
<property name="name" value="时倾"/>
</bean>
小结
- ByName 的时候,需要保证所有的
bean
的 id 唯一,并且这个bean需要和自动注入属性的 set 方法的值保持一致。 - ByType 的时候,需要保证所有的
bean
的 class 唯一,并且这个bean需要和自动注入属性的 类型保持一致。
7.4、注解实现自动装配
jdk 1.5 支持注解。Spring2.5就支持注解
The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.
要使用注解须知
- 导入约束。context约束
- 配置注解和支持
<context:annotation-config/>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
在属性上使用即可,也可以在 set 上使用
此时可以省略 set 方法,前提 是自动装配的属性在 IOC (Spring)容器中存在,且符合 ByType
✈️ 注意
在使用@Autowired时,首先在容器中查询对应类型的bean【ByType】
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
如果查询的结果不止一个,那么@Autowired会根据名称来查找。需要借助
@Qualifier
标记,来指定需要装配bean的名称【ByName】
public class Person {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
@Nullable //字段标记了这个注解,说明这个字段可以为 NULL
//如果显式的定义了 @autowired 的 required 为 false说明这个对象可以为空,否则不能为空
@Autowired(required = false)
private Cat cat;
借助@Qualifier
标记,来指定需要装配bean的名称@Qualifier(value = "xxx")
@Autowired
@Qualifier(value = "cat22")
private Cat cat;
@Autowired
@Qualifier(value = "dog22")
private Dog dog;
<bean id="cat22" class="com.lsw.pojo.Cat"/>
<bean id="dog22" class="com.lsw.pojo.Dog"/>
<bean id="cat11" class="com.lsw.pojo.Cat"/>
<bean id="dog11" class="com.lsw.pojo.Dog"/>
<bean id="person" class="com.lsw.pojo.Person"/>
<context:annotation-config/>
也就是说:如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value = “xxx”)去配合 @Autowired 的使用,指定一个唯一的bean 对象注入。
@Nullable
字段标记了这个注解,说明这个字段可以为 Null
@Resource
@Resource
是 java 原生自带的注解 ,其功能和 @Autowired
大致相同
当存在多个相同类型的对象时,也是可以通过指定 name 来进行指定特定类
效率相对于 @Autowired
比较低
@Resource(name = "cat")
private Cat cat;
@Resource
private Dog dog;
<bean id="cat" class="com.lsw.pojo.Cat"/>
<bean id="cat22" class="com.lsw.pojo.Cat"/>
<bean id="dog22" class="com.lsw.pojo.Dog"/>
小结
@Autowired
和@Resource
的区别:
@Autowired
与@Resource
都可以用来装配bean. 都可以写在属性字段上,或写在setter方法上。@Autowired
默认按照 ByType 来实现的,如果查找到多个,则按照 ByName 来查找。@Resource
默认按照 ByName 来实现的,如果查找到多个,则按照 ByType 来查找。@Autowired
按照名字进行查找的时候 需要借助@Qualifier(value = "xxx")
来标记
@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired() @Qualifier("baseDao") private BaseDao baseDao;
@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao") private BaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
*个人认为 @Resource 很难有个明确的默认,要是没有指定 name 就是安装 默认名字,没有找到则按照类型来,可不可以 认为 他就是默认按照类型的,要是需要按照名字来 需要进行指定。*纯属个人理解,如果说的不对,可以下方留言交流。
8、使用注解开发
在 Spring4 之后,要使用注解开发,要保证 AOP 的包导入了
在使用注解需要 导入 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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 指定要扫描的包,这个包下的注解就会生效!-->
<context:component-scan base-package="com.lsw"/>
<context:annotation-config/>
</beans>
1、bean
+ @Component : 组件,放在类上,说明这个类被Spring 管理了,就是bean 等价于 <bean id="user" class="com.lsw.pojo.User"/>
2、属性如何注入
+ @Value("李白") : 相当于<property name="name" value="李白"/>
//@Component 组件
//等价于<bean id="user" class="com.lsw.pojo.User"/>
@Component
public class User {
//@Value("李白")
//相当于<property name="name" value="李白"/>
public String name ;
@Value("李白")
public void setName(String name) {
this.name = name;
}
}
3、衍生的注解
@Component
有几个衍生注解,我们在web开发中,会按照 MVC 三层架构分层!
- dao层【
@Repository
】 - service层【
@Service
】 - controller层【
@Controller
】
这四个注解的功能都是一样的,都是代表将某个类注册到 Spring 中,装配 Bean
4、自动装配置
@Autowired
@Resource
5、作用域
@Scope("singleton")
——> 单例模式@Scope("prototype")
——>原型模式
6、小结
xml 与 注解
- xml 更加万能,适用于任何场合,维护简单方便
- 注解 不是自己的类无法使用,不能进行引用,维护相对复杂
最佳实践:
- xml 用来管理 bean
- 注解只完成属性的注入
- 我们在使用的过程中只需要注意一个问题,必须让注解生效,就需要开启注解支持。
<!-- 指定要扫描的包,这个包下的注解就会生效!-->
<context:component-scan base-package="com.lsw"/>
<context:annotation-config/>
9、使用java的方式配置Spring
@Configuration
【涉及到底层的关系】
我们现在要完全不使用Spring的xml配置了,全权交给 Java 来做
JavaConfig 是 Spring的一个子项目,在Spring4 之后,他成为了一个核心功能。
实体类
//@Component
//这个注解的意思,就是说明这个类被Spring接管了,注册到容器中
public class User {
private String name;
public String getName() {
return name;
}
@Value("时倾aaa")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置类
@Configuration
//这个也会被Spring 托管,注册到容器中,因为他本来就是一个@Component,@Configuration代表这是一个配置类,就和之前的beans.xml一样
@ComponentScan("com.lsw.pojo")
@Import(SqConfig2.class)
public class SqConfig {
@Bean
// 注册了一个bean,就相当于我们之前写的一个bean 标签。
// 这个方法的名字就相当于bean 标签中的id属性
// 这个方法的返回值就相当于bean标签中的class属性
public User getUser(){
return new User();//就是返回要注入到bean的对象!
}
}
测试类
public class MyTest {
public static void main(String[] args) {
// 如果我们完全使用了配置类的方式去做,我们就只能通过AnnotationConfig 上下文来获取容器。通过配置类的class对象加载
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SqConfig.class);
User getUser = context.getBean("getUser", User.class);
System.out.println(getUser.getName());
}
}
这种的纯 Java 配置方式,在Springboot中随处可见