Java框架之spring 的 AOP 和 IOC

写在前面

本文一起看下spring aop 和 IOC相关的内容。

1:spring bean核心原理

1.1:spring bean的生命周期

在这里插入图片描述

spring bean生命周期,参考下图:
在这里插入图片描述

我们来一步步的看下。

  • 1
    其中1构造函数就是执行类的构造函数完成对象的创建,如下:
public User() {
    System.out.println("User 被实例化");
}
  • 2
    2是通过xml配置或者是@Resource等相关注入bean的注解,从容器中获取相关的spring bean进行赋值,如下:

在这里插入图片描述

在这里插入图片描述

  • 3
    3BeanNameAware,其中BeanNameAware是一个接口,只定义了一个唯一的方法void setBeanName(String name);,如果bean实现了该接口,则会回调setBeanName方法并将当前bean的beanName作为参数传递进去,这样,bean就能够获取自己的名称了,如下:
@Component
public class TestAware implements BeanNameAware {
    private String name;
    
    @Override
    public void setBeanName(String name) {
        this.name = name;
        System.out.println("TestAware.setBeanName, name is: " + this.name);
    }
}
  • 4,5
    4,5类似于3,也都分别定义了相关的xxxAware接口,以及对应的setXxx抽象方法,如下:
public class TestAware implements BeanFactoryAware, ApplicationContextAware {
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("TestAware.setBeanFactory");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("TestAware.setApplicationContext");
    }
}
  • 6
    6是spring留给我们的一个扩展的口,对应的接口是BeanPostProcessor,定义了初始化前执行的方法postProcessBeforeInitailization和初始化后执行的方法postProcessAfterInitialization如下:
public interface BeanPostProcessor {
    // 1:在InitailizingBean的afterProperties方法执行之前执行
    // 2:在自定义的init方法执行之前执行
    // 3:接收的参数是bean本身以及bean的名称
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	// 1:在InitailizingBean的afterProperties方法执行之后执行
    // 2:在自定义的init方法执行之后执行
    // 3:接收的参数是bean本身以及bean的名称
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

使用BeanPostProcessor的方式也比较简单,只需要实现该接口,对前置bean处理和后置bean处理两个方法提供具体实现后,将实现类注册为spring bean就可以了,如下可能实现:

public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("before--实例化的bean对象:"+bean+"\t"+beanName);
		// 可以根据beanName不同执行不同的处理操作
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("after...实例化的bean对象:"+bean+"\t"+beanName);
		// 可以根据beanName不同执行不同的处理操作
		return bean;
	}
}
  • 7
    InitializingBean也是一个扩展接口,定义了一个方法afterProperties,是在bean的属性都设置完毕后调用的方法,可以在该接口检测不可为空属性是否有值等操作,接口定义如下:
package org.springframework.beans.factory;

// 1:在所有属性设置完毕后执行
// 2:可以检测强制属性是否设置完成
// 3:可以使用自定义的init方法作为该方式的替代品
public interface InitializingBean {
	void afterPropertiesSet() throws Exception;

}

使用实例如下:

public class MyInitializingBeanTest implements InitializingBean {
    private String name;
    private int age;

    @Override
    public void afterPropertiesSet() throws Exception {
        String newName = "李四的歌";
        System.out.println("修改name属性值从 " + this.name + " -> " + newName);
        // 修改name属性的值
        this.name = newName;
    }
    ...
}
  • 8
    自定义的初始化方法,在bean标签中通过init-method设置,如下:
public class MyBeanWithInitMethod {
    private String name;

    public void changeNameProp() {
        String newName = "李四的歌";
        System.out.println("通过init-method修改name属性值从 "
                + this.name + " -> " + newName);
        this.name = newName;
    }
    ...
}

<bean class="yudaosourcecode.studyhelp.MyBeanWithInitMethod"
        id="myBeanWithInitMethod" init-method="changeNameProp">
    <property name="name" value="张三的歌"/>
</bean>
  • 9
    参考6,只不过是在InitialiBean和自定义init初始化方法执行完毕之后执行。
  • 10
    使用期。
  • 11
    当容器关闭时执行操作的接口规范,一般用来执行一些释放资源,收尾等操作,接口定义如下
package org.springframework.beans.factory;

// 1:当bean销毁时想要释放资源可以让bean实现该接口
// 2:可以使用自定义销毁方法作为另一个选择
public interface DisposableBean {
	void destroy() throws Exception;
}

实例如下:

public class MyLifeCycleBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean#destroy被调用了。。。");
    }
}
  • 12
    类似于11,自定义销毁方法,如下:
public class MyLifeCycleBean {

    public void destroyMethdo(){
        System.out.println("destroy-method 被调用...");
    }
}

<bean id="lifeCycle" 
      class="yudaosourcecode.studyhelp.MyLifeCycleBean"
      destroy-method="destroyMethdo"/>

1.2:spring bean生命周期完整实例

  • BeanPostProcessor
public class BeanPostProcessor123 implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("6:BeanPostProcessor#postProcessBeforeInitialization被调用了。。。");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("9:BeanPostProcessor#postProcessAfterInitialization被调用了。。。");
        return bean;
    }

}
  • bean
public class MyLifeCycleBean implements BeanNameAware,
        BeanFactoryAware,
        ApplicationContextAware,
//        BeanClassLoaderAware,
//        BeanPostProcessor,
        InitializingBean,
        DisposableBean {
    private String test;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("5:ApplicationContextAware 被调用。。。");
    }

    // 普通方法
    public void display(){
//        System.out.println("普通类实例方法调用...");
        System.out.println("10:使用中。。。");
    }

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        System.out.println("2:依赖注入");
        this.test = test;
    }

    public MyLifeCycleBean() {
        System.out.println("1:构造函数");
    }
//    @Override
//    public void setBeanClassLoader(ClassLoader classLoader) {
//        System.out.println("BeanClassLoaderAware 被调用了。。。");
//    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("4:BeanFactoryAware 被调用了。。。");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3:BeanNameAware 被调用了。。。");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("11:DisposableBean#destroy被调用了。。。");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("7:InitializingBean#afterPropertiesSet被调用了。。。");
    }
//
//    @Override
//    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//        System.out.println("BeanPostProcessor#postProcessBeforeInitialization被调用了。。。");
//        return bean;
//    }
//
//    @Override
//    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//        System.out.println("BeanPostProcessor#postProcessAfterInitialization被调用了。。。");
//        return bean;
//    }

    public void initMethod(){
        System.out.println("8: init-method 被调用...");
    }

    public void destroyMethdo(){
        System.out.println("12:destroy-method 被调用...");
    }
}
  • 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">

    <bean id="lifeCycle" class="yudaosourcecode.studyhelp.MyLifeCycleBean"
          init-method="initMethod" destroy-method="destroyMethdo">
        <property name="test" value="test"/>
    </bean>

    <bean class="yudaosourcecode.studyhelp.BeanPostProcessor123"/>
</beans>
  • 测试
@Test
public void mylifecyclebeantest111() {
//        ClassPathResource resource
//                = new ClassPathResource("mylifecyclebeantest.xml");
//        XmlBeanFactory xbf = new XmlBeanFactory(resource);
    AbstractApplicationContext ac = new ClassPathXmlApplicationContext("mylifecyclebeantest.xml");
//        Closeable
    // 手动添加后置bean处理器
//        xbf.addBeanPostProcessor(new MyLifeCycleBean());
//        ac.addBeanPostProcessor(new BeanPostProcessor123());
//        ac.
//        MyLifeCycleBean lifeCycle
//                =
    ac.getBean("lifeCycle", MyLifeCycleBean.class).display();
//        lifeCycle.display();
    // 销毁容器
    ac.close();
}

运行:

1:构造函数
2:依赖注入
3:BeanNameAware 被调用了。。。
4:BeanFactoryAware 被调用了。。。
5:ApplicationContextAware 被调用。。。
6:BeanPostProcessor#postProcessBeforeInitialization被调用了。。。
7:InitializingBean#afterPropertiesSet被调用了。。。
8: init-method 被调用...
9:BeanPostProcessor#postProcessAfterInitialization被调用了。。。
10:使用中。。。
11:DisposableBean#destroy被调用了。。。
12:destroy-method 被调用...

对比如下图:

在这里插入图片描述

1.3:spring xml配置原理

这部分来看看下我们在xml配置的<bean>标签是如何解析为spring bean的,我们会定义如下的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">

    <bean id="lifeCycle" class="yudaosourcecode.studyhelp.MyLifeCycleBean"
          init-method="initMethod" destroy-method="destroyMethdo">
        <property name="test" value="test"/>
    </bean>

    <bean class="yudaosourcecode.studyhelp.BeanPostProcessor123"/>
</beans>

其中在<beans中声明的我们叫做是命名空间,然后在命名空间中就可以定义各种各样的标签,并定义了校验xml的xsd,为了解决通过互联网直接加载xsd慢,或者是加载不到的问题,定义了配置文件spring.schemas,配置了命名空间和对应的本地xsd文件的对应关系:

在这里插入图片描述

这样就可以直接从jar包中获取xsd文件了,那么标签如何解析呢?需要使用到spring.handlers,如下:

在这里插入图片描述

当然我们也可以自定义标签,同样也需要在spring.schemas中配置我们自己的xsd,以及并实现并配置解析对应标签的handler到spring.handles配置文件中,具体可以参考spring的自定义标签 一文。

1.4:spring bean配置方式演进

1.0/2.0 XML配置bean,@Autowire注解注入bean
2.5 @Service xml配置和注解配置bean方式混用的半自动注解配置
3.0 @Bean,@Condition Javaconfig方式配置bean
4.0 @Condition,@AutoConfigureX 全自动注解配置

在这里插入图片描述

2:spring AOP

通过前面分析的spring bean的功能,我们已经能够灵活地定义各种对象实例,并设置其各种依赖关系了,此时假定我们现在有类似于下面这样的需求:

1:怀疑某个方法执行的慢,影响性能,但又无法直接修改源代码看其耗时
2:想要记录某一批方法的调用日志,因为方法很多,一个个改的话非常麻烦
3:程序有bug,但是程序年代久远,源程序早已经遗失,但又必须解决

该怎么做呢?在计算机领域有这样一个至理名言,计算机领域所有的问题都可以通过加一层来解决,这里的问题可以吗?可以的,我们只要在方法执行的前和后都加一层就行了,如下:

在这里插入图片描述

spring为了实现这个加一层的功能就提供了对应的功能实现,首先我们需要定义要对那些方法加一层,通过如下红框方式来表示:

在这里插入图片描述

spring给其起个一个专门的名称切点,即要切的点,要拦截的方法,这样还不够,知道要对哪些方法加一层了,但是需要做什么呢,这个时候就可以这样定义:

在这里插入图片描述

spring也给其起了一个专门的名称通知,其中在方法执行前执行的叫做前置通知,在方法执行后执行的叫做后置通知,所有的同志加在一起,spring也起了一个专门的名称切面

以上这个实现加一层的功能,spring也提供了一个专门的名称,aspect oriented programming,即面向切面编程,即AOP。

写在后面

参考文章列表

Java 操作 XML(11)–XMLBeans 使用 。

spring的自定义标签 。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录再战day3

力扣 209移除链表 思路&#xff1a; 第一&#xff1a; 首先明白 链表中的元素是无法被真正的删除的 只能替换指针的指向的元素 第二&#xff1a; 这道题是说移除链表中的目标元素&#xff0c;需要创建一个虚拟节点dummy去始终指向我们的头节点&#xff0c;能够保证我们最后输出…

Yolov5-Face 原理解析及算法解析

YOLOv5-Face 文章目录 YOLOv5-Face1. 为什么人脸检测 一般检测&#xff1f;1.1 YOLOv5Face人脸检测1.2 YOLOv5Face Landmark 2.YOLOv5Face的设计目标和主要贡献2.1 设计目标2.2 主要贡献 3. YOLOv5Face架构3.1 模型架构3.1.1 模型示意图3.1.2 CBS模块3.1.3 Head输出3.1.4 stem…

Ubuntu连不上网,在windows安装docker后

在windows上安装docker后&#xff0c;会依赖于virtualbox虚拟机&#xff0c;并且有虚拟网络&#xff0c;与ubuntu虚拟机网络产生冲突。 解决办法&#xff0c;打开网络适配器&#xff0c;禁用VirtualBox网络 这个时候就可以了。 ubuntu上使用docker pull镜像的时候&#xff0c…

MongoDB简介

目录 1、NoSQL概述 2、什么是MongoDB 3、MongoDB特点 一、MongoDB安装&#xff08;docker方式&#xff09; 二、MongoDB安装&#xff08;普通方式&#xff09; 三、MongoDB 概念解析 1、NoSQL概述 NoSQL(NoSQL Not Only SQL)&#xff0c;意即反SQL运动&#xff0c;指的是…

【AcWing算法基础课】第二章 数据结构(部分待更)

文章目录 前言课前温习一、单链表核心模板1.1题目描述1.2思路分析1.3代码实现 二、双链表核心模板2.1题目描述2.2思路分析2.3代码实现 三、栈核心模板3.1题目描述3.2思路分析3.3代码实现 四、队列核心模板4.1题目描述4.2思路分析4.3代码实现 五、单调栈核心模板5.1题目描述5.2思…

短视频矩阵抖音账号矩阵系统源码开发者自研(一)

一、短视频矩阵系统源码框架建模搭建 目录 一、短视频矩阵系统源码框架建模搭建 1.抖音账号矩阵系统功能模型建模 2.短视频账号矩阵系统接口开发规则 二、短视频矩阵系统源码视频剪辑转码处理 短视频矩阵系统是一个多功能的视频内容管理系统&#xff0c;用于创建、剪辑发布…

charles unknown 问题和手机代理设置(iOS手机)

一、Charles下载 下载地址&#xff1a;https://www.charlesproxy.com/download/ 二、Charles配置代理 1.查看本机IP&#xff1a;help-->Local IP Address 2.查看或者设置访问端口&#xff1a;Proxy->Proxy Settings 3.设置不代理计算机的请求&#xff08;推荐&#xff0…

buuctf re(二)+ web CheckIn

目录 re xor helloword reverse3 web SUCTF 2019 CheckIn xor 1.查壳 64位&#xff0c;无壳 2.ida&#xff0c;f5查看伪代码 3.跟进global dq是八个字节&#xff0c;汇编数据类型参考汇编语言---基本数据类型_汇编db类型_wwb0111的博客-CSDN博客 4.因为global变量里有一…

蓝桥杯专题-试题版-【九宫重排】【格子刷油漆】【回文数字】【国王的烦恼】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

高级第二个月复习

1.route与router的区别 $route&#xff1a;获取路由信息 指当前路由实例跳转到的路由对象 包括&#xff1a; $route.path 字符串&#xff0c;等于当前路由对象的路径&#xff0c;会被解析为绝对路径&#xff0c;如/home/ews $route.name 当前路由的名字&#xff0c;如果没有使…

Flutter悬浮UI的设计Overlay组件

文章目录 APP开发经常要遇到的开发场景Overlay 的介绍Overlay的使用规则举例说明源码例子报错报错No Overlay widget found报错原因解决方法 修改后的源码 例子效果 APP开发经常要遇到的开发场景 有时候我们在开发APP的时候会遇到下面这些需求&#xff1a; 在现有页面上添加浮…

【记录】实践场景

Apache Doris 在京东搜索实时 OLAP 探索与实践 https://doris.apache.org/zh-CN/blog/JD_OLAP/ 通过对比开源的几款实时OLAP引擎&#xff0c;我们发现doris和clickhouse能够满足我们的需求&#xff0c;但是clickhouse的并发度太低是个潜在的风险&#xff0c;而且clickhouse的数…

css新特性(五)

css基础&#xff08;一&#xff09;css基础&#xff08;一&#xff09;_上半场结束&#xff0c;中场已休息&#xff0c;下半场ing的博客-CSDN博客Emmet语法Emmet语法_上半场结束&#xff0c;中场已休息&#xff0c;下半场ing的博客-CSDN博客css基础&#xff08;二&#xff09;c…

多元分类预测 | Matlab粒子群算法(PSO)优化混合核极限学习机(HKELM)分类预测,多特征输入模型,PSO-HKELM分类预测

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元分类预测 | Matlab粒子群算法(PSO)优化混合核极限学习机(HKELM)分类预测,多特征输入模型,PSO-HKELM分类预测 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matl…

面向切面编程-AOP

Aop 概述&#xff1a;Aspect Oriented Programming(面向切面编程、面向方面编程)&#xff0c;即面向特定的方法编程,对原有的方法进行附加、增强 动态代理是面向切面编程的主流实现 实现步骤 pom文件中导入AOP依赖 <dependency><groupId>org.springframework.…

Spring Boot中的事务隔离级别

Spring Boot中的事务隔离级别 介绍 Spring Boot是一个流行的Java框架&#xff0c;它提供了许多方便的注解和工具&#xff0c;使得数据库操作变得更加容易。其中&#xff0c;事务隔离级别是Spring Boot中一个非常重要的概念&#xff0c;它可以帮助开发者控制数据库操作的并发性…

Jmeter(jmeter-plugins插件的安装使用)

目录 一、安装JMter Plugins 二、Custom Thread Groups插件 Stepping Thread Group 元件 Ultimate Thread Group 一、安装JMter Plugins 1、官网下载 JMeter Plugins 的jar包 2. 将下载的jar包复制到 %JMETER_HOME%\lib\ext 目录下 3. 启动 JMeter --> Options -->…

Chrome/Edge 浏览器多账号登录,测试同一业务系统的不同账号角色

文章目录 如何使用多账户&#xff1f;ChromeEdge 虽然说用不同浏览器测试也比较方便、还能顺带测试多浏览器兼容问题…… 但我是开发呀&#xff0c;我只想用我最习惯的谷歌浏览器完成快速开发&#xff0c;把功能铺上&#xff0c;专注于业务逻辑的开发 这些浏览器差异等只会给我…

vue+elementui实现英雄联盟道具城

目录 一、效果图 1.首页 2.商品列表、分类 二、实现重点讲解 1.首页轮播图 1.1技术实现&#xff1a; 1.2.鼠标聚焦切换图片事件 2.首页tab切换 3.商品列表实现 三、项目结构说明 四、总结 一、效果图 1.首页 项目与官方效果没有太大差异&#xff1a; 游戏导航&#xff1…

【SQL应知应会】分析函数的点点滴滴(一)

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 分析函数的点点滴滴 1.什么是分析函数&#xff1a;…