五,Spring Bean生命周期

news2024/12/24 9:40:26

1 Spring Bean的生命周期(概念重点)

对象的生命周期:对象从生到死的过程。

Spring工厂中Bean的生命周期并不像想象的那么简单,Spring对工厂中的Bean的生命周期进行了细致的划分,并允许开发者通过编码或配置的方式定制Bean在生命周期的各个阶段的操作。

  1. 初始化阶段:在对象创建后,进行一些初始化操作,比如对属性值的检查
  2. 销毁阶段:在回收对象之前,执行一些销毁操作,比如资源的释放

1.1 初始化阶段

在Spring工厂创建对象并为属性赋值后就进入到了Bean的初始化阶段,Spring会自动调用Bean的初始化方法。在初始化方法中可以做一些初始化操作,比如对刚创建的对象进行检查操作。而初始化方法可以由开发者实现接口或者配置的方式定义。

实现InitializingBean接口

public class XxxServiceImpl implements XxxService, InitializingBean {
    private XxxDao xxxDao;

    public XxxServiceImpl() {
        System.out.println("XxxServiceImpl()");
    }

    public XxxDao getXxxDao() {
        return xxxDao;
    }

    public void setXxxDao(XxxDao xxxDao) {
        System.out.println("XxxServiceImpl.setXxxDao");
        this.xxxDao = xxxDao;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("XxxServiceImpl.afterPropertiesSet");
        if(xxxDao == null){
            throw new RuntimeException("xxxDao must not be null");
        }
    }
    ...
}

通过Bean标签的init-method属性

public class XxxServiceImpl implements XxxService, InitializingBean {
    private XxxDao xxxDao;

    public XxxServiceImpl() {
        System.out.println("XxxServiceImpl()");
    }

    public XxxDao getXxxDao() {
        return xxxDao;
    }

    public void setXxxDao(XxxDao xxxDao) {
        System.out.println("XxxServiceImpl.setXxxDao");
        this.xxxDao = xxxDao;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("XxxServiceImpl.afterPropertiesSet");
        if(xxxDao == null){
            throw new RuntimeException("xxxDao must not be null");
        }
    }

    private void initMethod(){
        System.out.println("XxxServiceImpl.init");
    }
    ...
}
<bean id="xxxDao" class="com.bz.dao.impl.XxxDaoImpl"/>
<bean id="xxxService" class="cbzl" init-method="initMethod">
    <property name="xxxDao" ref="xxxDao"/>
</bean>

InitializingBean接口和init-method属性的应用场景的区别:

接口方式:开发简单,一次实现,该类型的所有Bean配置都自动生效。

init-method属性:对于旧代码而言无需修改,即可完成对旧代码的配置。

实战中,二者一般不会同时出现,如果同时出现执行顺序:先接口中的方法,后init-method属性配置的方法。

1.2 销毁阶段

在关闭Spring工厂时,Spring会销毁其创建的对象,此时就进入到了Bean的销毁阶段。在此阶段,Spring会自动调用Bean的销毁方法,在对象销毁前执行一些操作,比如释放资源。

实现DisposableBean接口

public class XxxServiceImpl implements XxxService, InitializingBean, DisposableBean{
    ...
     @Override
    public void destroy() throws Exception {
        System.out.println("XxxServiceImpl.destroy");
    }
}

@Test
public void testInitializingBean(){
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    ctx.close();
}

通过Bean标签的destroy-method属性

public class XxxServiceImpl implements XxxService, InitializingBean, DisposableBean{
    ...
     @Override
    public void destroy() throws Exception {
        System.out.println("XxxServiceImpl.destroy");
    }
    
    public void destroyMethod(){
        System.out.println("XxxServiceImpl.destroyMethod");
    }
}
<bean id="xxxService" class="cbzl" init-method="initMethod" destroy-method="destroyMethod">
    <property name="xxxDao" ref="xxxDao"/>
</bean>

实战中,二者一般不会同时出现,如果同时出现执行顺序:先接口中的方法,后destroy-method属性配置的方法。

2 BeanPostProcessor(后置Bean处理)

BeanPostProcessor可以对Spring工厂中所有的Bean对象实例化后,对Bean对象再次加工处理。

编码

User.java

public class User implements Serializable, InitializingBean {
    private Integer userId;
    private String username;
    private String password;

    public User() {
    }

    public User(Integer userId, String username, String password) {
        this.userId = userId;
        this.username = username;
        this.password = password;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("User.afterPropertiesSet");
    }

    public void initMethod(){
        System.out.println("User.initMethod");
    }
    
    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

MyBeanPostProcessor.java

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    //在初始化阶段前调用
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
        if (bean.getClass() == User.class) {
            User user = (User)bean;
            user.setPassword("654321");
        }
        return bean;
    }

    @Override
    //在初始化阶段后调用
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
        return bean;
    }
}

配置

<bean id="u" class="com.bz.entity.User" init-method="initMethod">
    <property name="userId" value="1"/>
    <property name="username" value="xiaohei"/>
    <property name="password" value="123456"/>
</bean>

<bean class="com.bz.factory.MyBeanPostProcessor"/>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1NwDyJUg-1673778159260)(Spring%20day05.assets/image-20200824224909657.png)]

BeanPostProcessor可以对Spring中配置的所有Bean进行统一处理,并且Spring中可以配置多个BeanPostProcessor。

3 Spring AOP的实现原理

AOP:面向切面编程,灵活的动态的将额外功能添加到现有的原始对象上。

3.1 Spring AOP的实现方式

Spring AOP采用动态代理,将额外功能添加到原始对象中。

在这里插入图片描述

Spring的动态代理底层:JDK动态代理(默认)+CGLib动态代理。

3.2 JDK动态代理

JDK动态代理:面向接口编程

在这里插入图片描述

JDK动态代理要求原始类型必须实现的有接口。

@Test
public void testJDKProxy(){
    // 创建原始对象
    StudentService studentService = new StudentServiceImpl();
    // 定义额外功能
    java.lang.reflect.InvocationHandler handler = new java.lang.reflect.InvocationHandler(){
        /*
                proxy:生成的代理对象
                method: 原始方法
                args: 调用原始方法的参数
             */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //定义额外功能
            System.out.println("前置通知");
            Object result = null;
            try {
                //调用原始对象的方法
                result = method.invoke(studentService, args);
                System.out.println("后置通知");
            }catch(Exception e){
                System.out.println("异常通知");
                throw  e;
            }finally {
                System.out.println("最终通知");
            }
            return result;
        }
    };
    // 创建代理对象
    /*
            classLoader:类加载器
            interfaces: 原始类型实现的接口
            handler: 额外功能
         */
    StudentService proxy = (StudentService)Proxy.newProxyInstance(StudentService.class.getClassLoader(), studentService.getClass().getInterfaces(), handler);
    proxy.showStudents();
    System.out.println(proxy.getClass());
    System.out.println(proxy.getClass().getSuperclass());

}

类加载器的解释:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-URCUe9l9-1673778159262)(Spring day05.assets/image-20200407155251367.png)]

JDK生成的动态代理类型,实现了原始类型的接口,但同时继承了Proxy父类,只支持为面向接口编程的原始类型生成代理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VVz79S9y-1673778159263)(Spring day05.assets/image-20200407155409363.png)]

3.3 CGLib动态代理

CGLib支持面向接口和面向继承的代理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3fWi6we7-1673778159263)(Spring day05.assets/image-20200407161214142.png)]

@Test
public void testCGLib(){
    // 创建原始对象
    BookServiceImpl bookService = new BookServiceImpl();
    // 定义额外功能
    org.springframework.cglib.proxy.InvocationHandler handler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //定义额外功能
            System.out.println("前置通知");
            Object result = null;
            try {
                //调用原始对象的方法
                result = method.invoke(bookService, args);
                System.out.println("后置通知");
            }catch(Exception e){
                System.out.println("异常通知");
                throw  e;
            }finally {
                System.out.println("最终通知");
            }
            return result;
        }
    };
    // 生成代理对象
    Enhancer enhancer = new Enhancer();
    //设置代理类的夫类型
    enhancer.setSuperclass(BookServiceImpl.class);
    //设置额外功能
    enhancer.setCallback(handler);

    BookServiceImpl proxy = (BookServiceImpl)enhancer.create();
    proxy.showBooks();

    System.out.println(proxy.getClass());
    System.out.println(proxy.getClass().getSuperclass());

}

Spring默认使用JDK动态代理,如何设置Spring使用CGLib?

<aop:config proxy-target-class="true">
        <aop:pointcut id="servicePointcut" expression="execution(* com.bz.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
    </aop:config>

3.4 BeanPostProcessor技术

Spring何时使用动态代理生成代理对象?

​ Spring使用BeanPorstProcessor后置处理Bean,具体讲:就是在Spring工厂创建对象之后,对这个对象再次加工处理的过程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vuAKglc-1673778159264)(Spring day05.assets/image-20200407164533851.png)]

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("before");
        System.out.println("bean = [" + bean + "], beanName = [" + beanName + "]");

        if (bean.getClass() == User.class) {
            User user = (User)bean;
            user.setPassword("654321");
        }

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("after");
        System.out.println("bean = [" + bean + "], beanName = [" + beanName + "]");
        return bean;
    }
}

Spring中可以配置多个BeanPostProcessor.在内置BeanPostProcessor中根据切点和切面为特定的原始对象生成代理对象。

4 Spring事务控制的实现原理

4.1 JDBC中事务控制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0W3c5bdn-1673778159265)(Spring day05.assets/image-20200407141236505.png)]

第1次获取连接后将连接保存到线程对象中,接下来的多次获取直接从线程对象中获取同1个连接。保证service和dao使用同1连接,从而保证事务控制。

4.2 Spring事务控制的原理

Spring保证控制事务的连接和mybatis中执行sql的连接是同1个。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbriWG02-1673778159266)(Spring day05.assets/image-20200407144923391.png)]

TransactionManager: 获取连接,把连接保存到线程中。

MyBaits集成Spring后:sqlSession内部获取连接,优先从线程中获取。

保证了控制事务(Spring)的连接和执行SQL(MyBaits)的连接是同1个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165549.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu18 sqlyog配置mysql5.7远程连接

mysql 配置远程连接 1. mysql安装和配置 sudo apt-get install mysql-server-5.7 systemctl status mysql service mysql status修改mysql的配置文件&#xff1a; sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf以下为mysqld.cnf文件主要内容&#xff0c;这里的skip-grant-ta…

基于51单片机的pm2.5空气质量监测仪仿真设计

51单片机pm2.5监测仪仿真设计( proteus仿真程序报告讲解视频&#xff09; 仿真图proteus 7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0032 51单片机pm2.5监测仪仿真设计主要功能&#xff1a;讲解演示视频仿真程序设计…

代码整洁提升方案

验-言 公共方法都要做参数的校验&#xff0c;参数校验不通过明确抛出异常或对应响应码&#xff1a; Java Bean验证已经是一个很古老的技术了&#xff0c; 会避免我们很多问题&#xff1b; 在接口中也明确使用验证注解修饰参数和返回值&#xff0c; 作为一种协议要求调用方按…

win11 arm 系统安装安卓子系统

一般的x86电脑如果安装android子系统&#xff0c;运行安卓子系统&#xff0c;由于要将android arm代码转译为x86代码&#xff0c;所以效率不一定高&#xff0c;但是如果电脑是arm架构的&#xff0c;通过安卓子系统运行android的程序执行效率就会 高不少&#xff0c;本文参考,都…

JVM面试题

Java内存区域 说一下 JVM 的主要组成部分及其作用&#xff1f; JVM包含两个子系统和两个组件&#xff0c;两个子系统为Class loader(类装载)、Execution engine(执行引擎)&#xff1b;两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。 Class loader…

Es6的Promise

Promise是异步编程的一种解决方案。简单来说Promise就是一个用来存储数据的对象&#xff0c;它有着一套特殊的存取数据的方式。可以解决异步回调函数/回调地狱问题。创建Promise1.创建Promise时需要一个 回调函数 作为参数这个回调函数会在Promise时 自动调用2.调用回调函数时&…

基于matlab的指纹图像处理、脊线增强、脊线分割、脊线细化、细节点检测和细节点验证

需求分析对于指纹的特征提取包含几个步骤&#xff0c;脊线增强、脊线分割、脊线细化、细节点检测和细节点验证&#xff0c;本次大作业需要针对已经增强的指纹图片进行后续几个步骤&#xff0c;通过多种形态学算法进行分割、细化、细化后处理&#xff0c;找到其中的端点和分叉点…

elasticsearch基础2——es配置文件、jvm配置文件详解

文章目录一、配置文件详解1.1 elasticsearch.yml文件1.1. 1 基础参数1.1.1.1 自定义数据/日志目录1.1.1.2 锁定物理内存1.1.1.3 跨域设置1.1.1.4 其他参数1.1.2 集群类1.1.3 分片类1.1.4 IP绑定类1.1.5 端口类1.1.6 交互类1.1.5 Xpcak安全认证1.1.5.1 xpack内置用户1.1.5.2 xpa…

LabVIEW使用VI脚本向VI添加对象

LabVIEW使用VI脚本向VI添加对象可使用VI脚本向前面板和程序框图添加对象。该教程以向程序框图添加对象为例。按照下列步骤&#xff0c;通过VI脚本向VI添加对象。创建VI前&#xff0c;需先了解VI脚本的基本内容。必须启用VI脚本&#xff0c;才能显示VI脚本选板&#xff0c;使用相…

aws beanstalk 理解和使用eb工作线程环境

参考资料 beanstalk 工作线程环境beanstalk 工作线程环境管理https://catalog.us-east-1.prod.workshops.aws/workshops/b317e4f5-cb38-4587-afb1-2f75be25b2c0/en-US/03-provisionresources 理解 beanstalk 工作线程环境 https://docs.amazonaws.cn/elasticbeanstalk/latest…

【Java基础】-【线程】

文章目录创建线程的方式Thread类的常用方法run()和start()有什么区别&#xff1f;线程是否可以重复启动&#xff0c;有什么后果&#xff1f;线程的生命周期实现线程同步Java多线程之间的通信方式sleep()和wait()的区别notify()、notifyAll()的区别如何实现子线程先执行&#xf…

GaussDB(DWS)数据库的数据迁移实操【玩转PB级数仓GaussDB(DWS)】

GaussDB(DWS)数据库的数据迁移实操【玩转PB级数仓GaussDB(DWS)】 1.1先了解一下Gauss数据库 Gauss数据库并非完全自主开发。它可以看作是基于PostgreSQL 9.2的一次神奇的修改。正如Redhat和Android都源于LINUX的研发&#xff0c;IBM AIX和IOS都源于UNIX的研发一样&#xff0c;…

16、ThingsBoard-配置OAuth2

1、概述 如果你的系统想要接入第三方认证来登录,就像国内很多网站都支持微信、QQ等授权登录,其实thingsboard也提供了OAuth2.0来支持,ThingsBoard 是支持授权码授权类型来交换访问令牌的授权码,同时它自己也提供了几种方式 Google、GitHub、Facebook、Apple 同时也支持自定…

使用numpy进行深度学习代码实战

使用方法定义网络from net import ConvNet net ConvNet() if not net.load(MODEL_PATH): net.addConvLayout([3,3,1,4],bias True,paddingVAILD,init_typeinit_type,st_funcLEAKY_RELU_0.01)net.addConvLayout([3,3,4,8],bias True,paddingVAILD,init_typeinit_type,st…

weblogic反序列化之T3协议

前言 weblogic 的反序列化漏洞分为两种 &#xff0c;一种是基于T3 协议的反序列化漏洞&#xff0c;一个是基于XML的反序列化漏洞&#xff0c;这篇来分析一下基于T3 协议的反序列化漏洞。 环境搭建&#xff1a; [JAVA安全]weblogic反序列化介绍及环境搭建_snowlyzz的博客-CSDN…

Virtualbox设置固定IP

Virtualbox桥接实现静态固定IP内外网访问 super_kancy 2018-10-20 11:55:28 6024 收藏 7 展开 桥接实现静态固定IP内外网访问 第一步、安装好一个虚拟机linux01 第二步、配置网卡&#xff0c;选择桥接网卡模式&#xff0c;并且指定桥接的具体的网卡 第三步、正常启动虚拟机lin…

【Java集合】Collection 体系集合详解(ArrayList,LinkedList,HashSet,TreeSet...)

文章目录1. 概念2. 集合和数组的区别3. 集合的体系结构4. Collection父接口5. List 子接口6. List 实现类6.1 ArrayList 类6.2 Vector 类6.3 LinkedList 类6.4 ArrayList和LinkedList的区别7. Set 子接口8. Set 实现类8.1 HashSet 类8.2 TreeSet 类9. Collections 工具类Java编…

【链表经典题目】总结篇

【链表经典题目】总结篇1 虚拟头结点2 链表的基本操作3 反转链表4 删除倒数第N个节点5 链表相交6 环形链表总结【链表】关于链表&#xff0c;你该了解这些&#xff01; 1 虚拟头结点 在链表&#xff1a;听说用虚拟头节点会方便很多&#xff1f; 中&#xff0c;我们讲解了链表…

简单了解OSI网络模型

本文为学习笔记&#xff0c;根据了解需求摘抄自下篇文章 参考&#xff1a;原文地址 作者&#xff1a;sunsky303 目录 OSI模型 TCP/IP分层模型 OSI模型 OSI 模型(Open System Interconnection model)&#xff08;七层网络模型&#xff09;是一个由国际标准化组织提出的概念模…

职责链模式

职责链模式 1.职责链模式基本介绍 职责链模式&#xff08;Chain of Responsibility Pattern&#xff09;, 又叫 责任链模式&#xff0c;为请求创建了一个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。 职责链模式通常每个接收者都包含对另一个接收者…