1、生命周期

**Spring容器的 bean **的生命周期;

1.1 默认生命周期

1.1.1 生命周期

  1. 调用构造方法,创建实例对象;
  2. set方法,给实例对象赋值;
  3. init 初始化方法 初始化对象;(手写并配置到bean上init-method="")
  4. 使用容器中的bean对象;
  5. 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) +自动装配(注解)的更多相关文章

  1. 一步步剖析spring bean生命周期

    关于spring bean的生命周期,是深入学习spring的基础,也是难点,本篇文章将采用代码+图文结论的方式来阐述spring bean的生命周期,方便大家学习交流.  一  项目结构及源码 1. ...

  2. 大厂高频面试题Spring Bean生命周期最详解

    Spring作为当前Java最流行.最强大的轻量级框架.Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题.程序员应该都知道Sprin ...

  3. spring之生命周期

    1.容器中对的生命周期 spring可以管理 singleton作用域的bean的生命周期,spring可以精确地知道该bean何时被创建,何时被初始化完成,容器合适准备销毁该bean实例. spri ...

  4. Spring Bean生命周期,好像人的一生。。

    大家好,我是老三,上节我们手撸了一个简单的IOC容器五分钟,手撸一个Spring容器!,这节我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 简单说说IoC和Bean IoC ...

  5. Spring的生命周期

    转:https://blog.csdn.net/liuxilil/article/details/4676088 Spring的生命周期. 容器启动,实例化所有实现了BeanFactoyPostPro ...

  6. Spring点滴四:Spring Bean生命周期

    Spring Bean 生命周期示意图: 了解Spring的生命周期非常重要,我们可以利用Spring机制来定制Bean的实例化过程. -------------------------------- ...

  7. Spring Bean 生命周期之destroy——终极信仰

    上一篇文章 Spring Bean 生命周期之我从哪里来 说明了我是谁? 和 我从哪里来? 的两大哲学问题,今天我们要讨论一下终极哲学我要到哪里去? 初始化 Spring Bean 有三种方式: @P ...

  8. 常见问题:Web/Servlet生命周期与Spring Bean生命周期

    Servlet生命周期 init()初始化阶段 Servlet容器加载Servlet(web.xml中有load-on-startup=1;Servlet容器启动后用户首次向Servlet发请求;Se ...

  9. spring bean 生命周期和 ? 作用域? spirng bean 相互依赖? jvm oom ? jvm 监控工具? ThreadLocal 原理

    1. spring bean 生命周期 1. 实例化一个bean ,即new 2. 初始化bean 的属性 3. 如果实现接口 BeanNameAware ,调用 setBeanName 4. Bea ...

随机推荐

  1. 清除 GitHub 历史记录的隐私信息

    清理 github 敏感信息 有的时候我们在提交到github上的内容不小心含有敏感代码,比如密码,公司的服务器IP等.这个时候就要通过一些手段清除这些信息. GitHub官方方案比较码放,所以推荐使 ...

  2. ExtJS直接加载HTML页面

    ExtJS直接加载HTML页面 说明 ExtJS组件很不错,但再完美也有需要其他组件的时候,比如有时候就需要引入已经写好的HTML页面.主要的方法如下. 测试环境:ExtJS 7.4 使用html配置 ...

  3. ubuntu下连microsoft sql server解决方案

    shell for MSSQL: https://github.com/dbcli/mssql-cli mssql-cli -S 127.0.0.1,1433 -d testDB -U myuser ...

  4. vue 使用npm install安装依赖失败 【问题分析与解决】

    1 进入项目根目录,先通过 npm install 命令安装项目所需依赖,再通过 vue ui 命令打开 Vue Cli 提供的图形化界面,选择项目所在文件夹将项目导入. 出现问题 npm insta ...

  5. 前端环境搭建nodejs%VScode

    nodejs:https://blog.csdn.net/antma/article/details/86104068VScode:https://code.visualstudio.com/Down ...

  6. RPA应用场景-信用卡交易争议后续流程

    RPA应用场景-信用卡交易争议后续流程 场景概述 信用卡交易争议后续流程 所涉系统名称 客服系统,邮件 人工操作(时间/次) 4小时 所涉人工数量20操作频率 不定时 场景流程 1.RPA自动接收客户 ...

  7. Nginx防御CC攻击

    CC攻击可以归为DDoS攻击的一种.他们之间都原理都是一样的,即发送大量的请求数据来导致服务器拒绝服务,是一种连接攻击.CC攻击又可分为代理CC攻击,和肉鸡CC攻击.代理CC攻击是黑客借助代理服务器生 ...

  8. tauri+vue开发小巧的跨OS桌面应用-股票体检

    最近打算写一个用于股票体检的软件,比如股权质押比过高的股票不合格,ROE小于10的股票不合格,PE大于80的股票不合格等等等等,就像给人做体检一样给股票做个体检.也实现了一些按照技术指标.基本面自动选 ...

  9. JDBC:获取自增长键值的序号

    1.改变的地方  实践: package com.dgd.test; import java.io.FileInputStream; import java.io.FileNotFoundExcept ...

  10. Windows安装face_recognition

    安装提供的python和cmake,最好都添加一下环境变量 安装dlib,pip install dlib-19.7.0-cp36-cp36m-win_amd64.whl 安装face_recogni ...