Spring(二)-生命周期 + 自动装配(xml) +自动装配(注解)
1、生命周期
**Spring容器的 bean **的生命周期;
1.1 默认生命周期
1.1.1 生命周期
- 调用构造方法,创建实例对象;
- set方法,给实例对象赋值;
- init 初始化方法 初始化对象;(手写并配置到bean上init-method="")
- 使用容器中的bean对象;
- destroy 销毁方法 销毁对象 (手写并配置到bean上destroy-method="")
1.1.2 bean 实体类
Truck
@Data
@ToString
public class Truck {
//品牌
private String brand;
//厂商
private String factory;
//价格
private Double price;
public Truck() {
//空参构造方法,观察bean什么时候实例化
System.out.println("------ 1.调用构造方法,创建实例对象 ------\n");
}
public void setBrand(String brand) {
//任意一个set方法,观察bean什么时候注入参数
System.out.println("------ 2.set方法,给实例对象赋值 ------");
this.brand = brand;
}
public void initTruck(){
//init初始化方法,观察bean什么时候初始化
//需要再配置bean的时候,配置init初始化方法
System.out.println("------ 3.Truck init 初始化方法 初始化对象 ------\n");
this.brand = "大运";
}
public void destroyTruck(){
//destory方法,观察bean什么时候销毁
//需要再配置bean的时候,配置destory销毁方法
System.out.println("------ 5.Truck destroy 销毁方法 销毁对象 ------\n");
}
//这里方法上标注的序号是测试后得来的;
}
1.1.3 bean 配置
spring-lifecycle.xml
<!-- spring容器中bean的生命周期 默认生命周期 -->
<bean id="truck" class="com.kgc.spring.lifecycle.Truck" init-method="initTruck" destroy-method="destroyTruck">
<property name="brand" value="江淮"></property>
<property name="factory" value="安徽"></property>
<property name="price" value="200000"></property>
</bean>
1.1.4 测试
public class TestSpringLifeCycle {
//定义全局容器对象,如果需要关闭容器对象,
//必须使用ApplicationContext的子接口 ConfigurableApplicationContext
//ApplicationContext接口主要各种属性的get方法;
//ConfigurableApplicationContext重在对各种属性的配置;
// private ApplicationContext context;
private ConfigurableApplicationContext context;
@Before
public void initApplicationContext(){
context = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
}
//测试spring 容器的bean的生命周期,默认和加了处理器两种场景
@Test
public void testSpringBeanLifeCycle(){
//从容器中,获取Truck的是实例对象
Truck truck = context.getBean("truck", Truck.class);
//使用对象
System.out.println("------ 4.使用容器中的bean对象"+truck +" ------");
//关闭容器
context.close();
}
}
输出结果:
//可以得出 spring中bean的 默认生命周期
------ 1.调用构造方法,创建实例对象 ------
------ 2.set方法,给实例对象赋值 ------
------ 3.Truck init 初始化方法 初始化对象 ------
------ 4.使用容器中的bean对象Truck(brand=大运, factory=安徽, price=200000.0) ------
------ 5.Truck destroy 销毁方法 销毁对象 ------
1.1.5 ApplicationContext 和 ConfigurableApplicationContext
参考博客:ApplicationContext和ConfigurableApplicationContext解析
ApplicationContext接口主要 各种属性的get方法;
ConfigurableApplicationContext重在对 各种 属性的配置;
1.2 增加后置处理器
1.2.1 生命周期
1.调用构造方法,创建实例对象;
2.set方法,给实例对象赋值;
3-1.后置处理的 before 方法;
3.初始化方法 初始化对象;
3+1.后置处理器的的 after 方法;
4.使用容器中的bean对象;
5.destroy 销毁方法 销毁对象;
1.2.2 后置处理器
要求:必须实现 BeanPostProcessor 接口
自定义 bean 的 后置处理器,对容器中所有的bean统一处理(生效),
要生效的话,必须将此处理器放到容器中(配置到spring的核心配置文件中,增加处理器的实例配置);
注意:
当前案例,只对容器中的一个实例处理;
MyBeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//在容器中bean的实例对象调用 初始化方法 前 自动调用(init方法可以没有,不影响)
//模拟处理容器中的bean,接下来的写法,仅限于当前的用法案例(容器中就 只有一个 卡车实例)
Truck truck = (Truck)bean;
System.out.println("++++++ 容器中的卡车对象 "+truck+"++++++");
System.out.println("++++++ 3-1,后置处理的 before 方法 ++++++");
truck.setBrand("后置处理的before方法");
System.out.println("++++++ 处理后的 卡车对象 "+truck+" ++++++\n");
return truck;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//bean 初始化方法 执行 后,调用此方法处理bean
Truck truck = (Truck)bean;
System.out.println("++++++ 初始化容器中的卡车对象 "+truck+"++++++");
System.out.println("++++++ 3+1,后置处理器的的 after 方法 ++++++");
truck.setBrand("after");
System.out.println("++++++ 初始化后 处理后的 卡车对象 "+truck+" ++++++\n");
return truck;
}
}
1.2.3 bean 配置
在配置文件中配置 MyBeanPostProcessor;
<!-- 配置后置处理器的实例,自动放入容器中,可以自动生效 (容器中所有的实例生效) -->
<bean class="com.kgc.spring.lifecycle.MyBeanPostProcessor"></bean>
1.2.4 测试
跟默认生命周期的测试代码一致;
输出结果:
------ 1.调用构造方法,创建实例对象 ------
------ 2.set方法,给实例对象赋值 ------
++++++ 容器中的卡车对象 Truck(brand=江淮, factory=安徽, price=200000.0)++++++
++++++ 3-1,后置处理的 before 方法 ++++++ ------ 2.set方法,给实例对象赋值 ------
++++++ 处理后的 卡车对象 Truck(brand=后置处理的before方法, factory=安徽, price=200000.0) ++++++
------ 3.Truck init 初始化方法 初始化对象 ------
++++++ 初始化容器中的卡车对象 Truck(brand=大运, factory=安徽, price=200000.0)++++++
++++++ 3+1,后置处理器的的 after 方法 ++++++ ------ 2.set方法,给实例对象赋值 ------
++++++ 初始化后 处理后的 卡车对象 Truck(brand=after, factory=安徽, price=200000.0) ++++++
------ 4.使用容器中的bean对象Truck(brand=after, factory=安徽,
------ 5.Truck destroy 销毁方法 销毁对象 ------
1.2.3 BeanPostProcesso
参考博客:BeanPostProcessor简介
BeanPostProcessor官方定义为工厂钩子,我们也俗称后置处理器。它允许自定义修改新的bean实例,例如检查标记接口或用代理包装它们。应用程序上下文可以在其bean定义中自动检测BeanPostProcessor bean,并将它们应用于随后创建的任何bean。
BeanPostProcessor 的 前置处理 和 后置处理;
![image-20220826150821502](Spring-02 生命周期 + 自动装配(xml) +自动装配(注解).assets/image-20220826150821502.png)
2、自动装配(xml)
2.1 bean 实体类
Person
@Data
public class Person {
//昵称
private String nickName;
//车子
private Car car;
//房子
private House house;
}
Car
@Data
public class Car {
//品牌
private String brand;
//厂商
private String factory;
//价格
private Double price;
}
House
@Data
public class House {
//户型
private String type;
//面积
private double area;
//价格
private Integer price;
}
2.2 bean 配置 (byType)
autowire="byType":根据属性 的 类型自动装配;
spring-auto.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- spring的自动装配方式,基于xml配置文件方式,掌握 -->
<!-- 容器中实例化一个容器的Car对象 -->
<bean id="car" class="com.kgc.spring.auto.Car">
<property name="brand" value="Bnw520"></property>
<property name="factory" value="华晨"></property>
<property name="price" value="450000"></property>
</bean>
<!-- 容器中实例化一个容器的House对象 -->
<bean id="house" class="com.kgc.spring.auto.House">
<property name="type" value="三室一厅"></property>
<property name="area" value="96"></property>
<property name="price" value="2800000"></property>
</bean>
<!-- 根据类型自动装配 -->
<bean id="person" class="com.kgc.spring.auto.Person" autowire="byType">
<property name="nickName" value="huayu"></property>
</bean>
</beans>
2.3 测试
public class TestSpringAutoUserXml {
private ApplicationContext context;
@Before
public void initApplicationContext(){
context = new ClassPathXmlApplicationContext("spring-auto.xml");
}
@Test
public void testSpringAuto(){
Person person = context.getBean("person", Person.class);
//使用对象
System.out.println("容器中的person对象:"+person);
}
}
输出结果:
容器中的person对象:Person(
nickName=huayu,
car=Car(brand=Bnw520, factory=华晨, price=450000.0),
house=House(type=三室一厅, area=96.0, price=2800000)
)
2.4 bean 配置 (多个同类型bean)
bean 配置:
其他不变,多增加一个Car类型的实例bean;
<bean id="car" class="com.kgc.spring.auto.Car">
<property name="brand" value="Bnw520"></property>
<property name="factory" value="华晨"></property>
<property name="price" value="450000"></property>
</bean>
<bean id="carNew" class="com.kgc.spring.auto.Car">
<property name="brand" value="AudiA6"></property>
<property name="factory" value="一汽"></property>
<property name="price" value="450000"></property>
</bean>
测试,报错信息:
No qualifying bean of type 'com.kgc.spring.auto.Car' available: expected single matching bean but found 2: car,carNew
总结
:autowire="byType" 当有多个相同类型的bean时,无法确定要装配的 bean;
2.5 bean 配置(byName)
其他配置信息不变,设置 autowire="byName" ,根据 属性 的 名字 自动装配;
<bean id="person" class="com.kgc.spring.auto.Person" autowire="byName">
<property name="nickName" value="hauyu"></property>
</bean>
测试输出结果:
容器中的person对象:Person(
nickName=huayu,
car=Car(brand=Bnw520, factory=华晨, price=450000.0),
house=House(type=三室一厅, area=96.0, price=2800000)
)
总结
:
- byType:根据类型自动装配:
- 根据实体属性的 类型,到容器中,根据 bean类型 进行唯一匹配,如果可以匹配到对应类型的bean的实例,就会执行自动装配, 如果不能唯一匹配(同类型的bean有多个),会报错;
- byName: 根据名称自动装配:
- 根据属性的 属性名,到容器中,根据 bean的id 属性值,进行唯一匹配,如果能够成功匹配,执行自动装配, 如果匹配不到,不执行自动装配,实体属性为null;
3、自动装配 (注解)
3.1 注解
- @Component 普通组件注解;
- @Repository 持久层注解
- @Service 业务层注解
- @Controller 控制层注解
3.3.1 注解的原理
默认情况下:spring自动将分层组件(@Controller,@Service,@Repository,@component)标识的类(不是接口),自动创建实例对象放入容器中,使用bean的标识id值为 对应类名首字母小写 就相当于,帮我们手动添加了配置 :
<bean id="分层注解标识类的类名首字母小写" class="分层注解标识类的全类名"> ... <bean>
3.1.2 自定义id 属性
如果不想使用默认的类名首字母小写,我们可以使用注解的value属性执行一个自定义的id值;
比如:@Service(value="自定义的id值"),注解只有value属性,可以省略value执行,简化为@Service("自定义的id值")
3.1.3 分层组件的目的
分层组件的目的,就仅仅是为了方便开发人员明确当前注解所在的类所对应的角色,在使用上,建议使用,按照官方定义的使用,防止模糊不清;在springMVC框架中@Controller有特殊含义;
3.2 配置文件
spring创建容器对象时,如果解析到 component-scan 组件扫描配置,会将base-package指定的基包(父包)及其子包所有增加了分层组件的类,自动创建实例,放进容器中;
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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
">
<!-- 组件扫描:注解标识的组件,必须通过组件扫描配置,才可以添加到spring的容器中-->
<context:component-scan base-package="com.kgc.spring.acnocation" > </context:component-scan>
</beans>
3.3 默认id属性 测试
3.3.1 实体
@Component
public class User {
//用户名
@Value("huayu") //@Value() 自动装配参数
private String userName;
//用户密码
@Value("123")
private String userPwd;
}
3.3.2 测试
@Test
public void testSpringAutoUserAnnotation(){
User user = context.getBean("user", User.class);
System.out.println(user);
//User(userName=huayu, userPwd=123)
}
3.4 自定义id属性 测试
3.4.1 实体(自定义id属性)
@Component(value = "myUser")
public class User {
//用户名
private String userName;
//用户密码
private String userPwd;
}
3.4.2 测试
@Test
public void testSpringAutoUserAnnotation(){
//User user = context.getBean("user", User.class);
//自定义id后,默认id不能使用: No bean named 'user' available
//必须使用自定义id
User user = context.getBean("myUser", User.class);
System.out.println(user);
//User(userName=huayu, userPwd=123)
}
3.5 自动装配
3.5.1 @Autowired
- 组件自动装配,可以实现实体属性类型的自动装配,自动到spring的容器中,根据当前属性的类型或者名称进行注入,如果容器中能匹配到,就直接将实例对象注入到当前实体属性上,无序手动指定;
- @Autowired自动装配原理:首先会根据byType方式,进行自动装配,
- 如果不能唯一匹配(存在同类型多个实例对象),会再次尝试使用byName方式,根据当前实体属性名,到容器中进行匹配(容器中bean的id值),如果能唯一匹配,直接执行自动装配,
- 默认情况下,@Autowired注解标识的实体属性,必须被装配
- 如果装配失败,就直接抛出异常;
- 如果不需要校验必须被装配(项目启动,如果装配失败,项目是起不来);
- 通过指定required = false,去除必须执行自动装配的校验(即便容器中找不到装配的实例,也不会抛出异常);
- 如果自动装配,容器中存在多个同类型的bean对象,可以使用注解@Qualifier("容器中同类型多个bean的某个id值"),实现指定到容器中,找对应的bean实例对象,进行自动装配;
- 底层是如何做的:在指定要扫描的包时,<context:component-scan> 元素会自动注册一个bean的后置处理器:AutowiredAnnotationBeanPostProcessor的实例。该后置处理器可以自动装配标记了@Autowired、@Resource或@Inject注解的属性。
3.5.2 实体
People
@Data
@Component("myPeople")
public class People {
//昵称
@Value("huayu")
private String name;
//玩具
@Autowired
private Toy toy;
}
Toy接口
public interface Toy {
//得到玩具
public void getToy();
}
ToyImpl1
@Component("toy1")
public class ToyImpl1 implements Toy {
@Value("玩具车")
private String toyName;
@Override
public void getToy() {
System.out.println(this.toyName);
}
}
3.5.3 测试
注意
:可以通过接口类型获取实现类(推荐使用);
@Test
public void testAutowired (){
People people = context.getBean("myPeople", People.class);
people.getToy().getToy(); //玩具车
}
3.5.4 存在多个相同类型的bean
当存在多个相同类型的bean,不能唯一匹配,会自动装配错误;
在写一个Toy实现类,ToyImpl2
@Component("toy2")
public class ToyImpl2 implements Toy {
@Value("尤克里里")
private String toyName;
@Override
public void getToy() {
System.out.println(this.toyName);
}
}
3.5.4.1 测试
报错信息(项目无法启动):
No qualifying bean of type 'com.kgc.spring.acnocation.bean.Toy' available: expected single matching bean but found 2: toy1,toy2
主要信息:类型无法唯一匹配;
3.5.4.2 required = false 允许不装配
People
@Data
@Component("myPeople")
public class People {
//昵称
@Value("huayu")
private String name;
//玩具
@Autowired (required = false)
private Toy toy;
}
项目可以启动但是还是报错(一般项目中不会有两个相同类型的实现类;)
3.5.4.3 @Quailfy
People
@Data
@Component("myPeople")
public class People {
//昵称
@Value("huayu")
private String name;
//玩具
@Autowired
@Qualifier("toy2") //指定bean的id值
private Toy toy;
}
3.5.4.4 测试
@Test
public void testAutowired (){
People people = context.getBean("myPeople", People.class);
System.out.println(people.getToy());
//com.kgc.spring.acnocation.bean.ToyImpl2@15d9bc04
people.getToy().getToy();
//尤克里里
}
3.6 指定扫描 排除扫描
3.6.1 指定扫描
include-filter
指定扫描(包含扫描):
- 只会扫描指定的类或者某类组件(使用分组扫描),加入到容器中;
- 但是必须配合父标签的user-default-filter使用,默认值是true,就是全部扫描;
- 指定扫描,如果要生效必须改为false;
- 指定扫描某类组件,type="annotation" expression="某类组件注解的全类名";
- 指定扫描某个类,type="assignable" expression="某个类的全类名";
3.6.1.1 指定扫描某类组件
type="annotation"
- org.springframework.stereotype.Component
- org.springframework.stereotype.Repository
- org.springframework.stereotype.Service
- org.springframework.stereotype.Controller
<!-- 指定扫描 @Component 组件 -->
<context:component-scan base-package="com.kgc.spring.acnocation" use-default-filters="false" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
3.6.1.2 指定扫描某个类
type="assignable"
<!-- 指定扫描 ToyImpl1 -->
<context:component-scan base-package="com.kgc.spring.acnocation" use-default-filters="false" >
<context:include-filter type="assignable" expression="com.kgc.spring.acnocation.bean.ToyImpl1"/>
</context:component-scan>
3.6.2 排除扫描
exclude-filter
- 排除扫描(剔除扫描):排除指定的类或某类组件,不加入到容器中,处理排除外的其他组件,仍然会被添加到容器中;
- 不需要配合父标签,use-default-filters="true" 因为,默认就是在全部扫描的基础上剔除;
- 排除扫描某类组件,type="annotation" expression="某类组件注解的全类名";
- 排除扫描某个类,type="assignable" expression="某个类的全类名";
3.6.2.1 排除扫描某类组件
type="annotation"
<!-- use-default-filters="true" 可写可不写 -->
<!-- 排除扫描 @Component组件 -->
<context:component-scan base-package="com.kgc.spring.acnocation" use-default-filters="true" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
3.6.2.2 排除扫描个类
type="assignable"
<!-- 排除扫描 ToyImpl1 -->
<context:component-scan base-package="com.kgc.spring.acnocation" >
<context:exclude-filter type="assignable" expression="com.kgc.spring.acnocation.bean.ToyImpl1"/>
</context:component-scan>
Spring(二)-生命周期 + 自动装配(xml) +自动装配(注解)的更多相关文章
- 一步步剖析spring bean生命周期
关于spring bean的生命周期,是深入学习spring的基础,也是难点,本篇文章将采用代码+图文结论的方式来阐述spring bean的生命周期,方便大家学习交流. 一 项目结构及源码 1. ...
- 大厂高频面试题Spring Bean生命周期最详解
Spring作为当前Java最流行.最强大的轻量级框架.Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题.程序员应该都知道Sprin ...
- spring之生命周期
1.容器中对的生命周期 spring可以管理 singleton作用域的bean的生命周期,spring可以精确地知道该bean何时被创建,何时被初始化完成,容器合适准备销毁该bean实例. spri ...
- Spring Bean生命周期,好像人的一生。。
大家好,我是老三,上节我们手撸了一个简单的IOC容器五分钟,手撸一个Spring容器!,这节我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 简单说说IoC和Bean IoC ...
- Spring的生命周期
转:https://blog.csdn.net/liuxilil/article/details/4676088 Spring的生命周期. 容器启动,实例化所有实现了BeanFactoyPostPro ...
- Spring点滴四:Spring Bean生命周期
Spring Bean 生命周期示意图: 了解Spring的生命周期非常重要,我们可以利用Spring机制来定制Bean的实例化过程. -------------------------------- ...
- Spring Bean 生命周期之destroy——终极信仰
上一篇文章 Spring Bean 生命周期之我从哪里来 说明了我是谁? 和 我从哪里来? 的两大哲学问题,今天我们要讨论一下终极哲学我要到哪里去? 初始化 Spring Bean 有三种方式: @P ...
- 常见问题:Web/Servlet生命周期与Spring Bean生命周期
Servlet生命周期 init()初始化阶段 Servlet容器加载Servlet(web.xml中有load-on-startup=1;Servlet容器启动后用户首次向Servlet发请求;Se ...
- spring bean 生命周期和 ? 作用域? spirng bean 相互依赖? jvm oom ? jvm 监控工具? ThreadLocal 原理
1. spring bean 生命周期 1. 实例化一个bean ,即new 2. 初始化bean 的属性 3. 如果实现接口 BeanNameAware ,调用 setBeanName 4. Bea ...
随机推荐
- VTK 在WINDOWS上的安装使用
参考:http://www.vtk.org/Wiki/VTK/Building/Windows#Step_5_-_Open_the_Visual_Studio_project
- .NET中如何在同步代码块中调用异步方法
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 在同步代码块中调用异步方法,方法有很多. 一.对于有返回值的Task 在同步代码块中直接访问 Task 的 Result ...
- 网心云在PVE下三种磁盘IO模式(No cache,Write through,Write back)选择与优化指南
---------------------------------------------------------------------------------------------------- ...
- redis如何实现数据同步
redis如何实现数据同步 两种,1全同步,2部分同步 全备份: 在slave启动时会向master发送sync消息,master收到slave这条消息之后,将启动后台备份进程,备份完成之后,将备份数 ...
- SQLite数据库损坏及其修复探究
数据库如何发生损坏 SQLite 数据库具有很强的抗损坏能力.在执行事务时如果发生应用程序崩溃.操作系统崩溃甚至电源故障,那么在下次访问数据库文件时,会自动回滚部分写入的事务.恢复过程是全自动的, ...
- 《阿里云天池大赛赛题解析》——O2O优惠卷预测
赛事链接:https://tianchi.aliyun.com/competition/entrance/231593/introduction?spm=5176.12281925.0.0.7e157 ...
- 【Python】和【Jupyter notebook】的正确安装方式?
学了那么久Python,你的Python安装方式正确吗?今天给你看看什么才是Python正确的安装方式,教程放在下面了,喜欢的记得点赞. Python安装 Python解答Q群:660193417## ...
- 自定义 systemd service
Red Hat Linux 自 7 版本后 采用systemd 形式取代原先 init ,用户可以参考 系统service 创建自己的service ,以便于日常统一管理,系统service 存储路径 ...
- resultMap自定义映射(一对多)
collection:处理一对多和多对多的关系 1) POJO中的属性可能会是一个集合对象,我们可以使用联合查询,并以级联属性的方式封装对象.使用collection标签定义对象的封装规则 publi ...
- java使用配置skywalking
一 .elasticsearch 和elasticsearch-head 1.下载 elasticsearch-6.3.1 ,下载地址 :https://pan.baidu.com/s/1ymxy ...