Spring注解(AOP)
底层动态代理
程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
导入aop的相关模块
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
动态感知业务类运行的状态
通知: 前置 @Before 后置 @After 环绕 @Around 异常@AfterThrowing 返回 @AfterReturning
补充环绕通知: 动态代理,手动推进目标方法运行(joinPoint.proceed() )
步骤:
编写切面类
在切面类里面 把每个方法 何时何地切入都指定好
将切面类和业务逻辑类 都添加到容器中
告诉容器 哪个是切面类@Aspect
在 xml中 <aop: aspectj-autoproxy> </aop:aspectj-autoproxy> 开启基于注解版的切面功能
注解中: 在当前的配置类加入 @EnableAspectJAutoProxy 启用基于注解的aop模式
正常代码:
@Component
public class Mathcalculator {
public int div(int i , int j) {
System.out.println("Mathcalculator--div被调用");
return i/j;
}
}
切面类:
@EnableAspectJAutoProxy
@Configuration
public class AOPConfig {
@Bean //业务逻辑类注册到容器
public Mathcalculator mathcalculator() {
return new Mathcalculator();
} @Bean // 切面类注册到容器中
public LogAspects logAspects() {
return new LogAspects();
}
}
测试:
public class test {
@Test
public void test01(){
//使用无参构造器 创建applicationContext (详情自己研究下有参构造器的方法)
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(AOPConfig.class);
Mathcalculator bean = applicationContext.getBean(Mathcalculator.class);
bean.div(1, 1);
//设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev","test"); //可以设置多个
//注册主配置类
applicationContext.register(Profile.class);
//启动刷新容器
applicationContext.refresh();
}
}
结果:

升级:
切面类
@Aspect
public class LogAspects {
//抽取公共的切入点表达式 本类的 如果是别的类的 写全名就OK了 @Pointcut("execution(public int com.toov5.config.Mathcalculator .*(..))" )
public void pointCut() { }
// @Before("public int com.toov5.config.Mathcalculator.div(int , int)")
@Before( "pointCut()" )
public void logStart(JoinPoint joinpoint) { //获取签名 获取方法
Object[] args = joinpoint.getArgs(); //目标方法 运行时候需要的参数表
System.out.println("除法运行@Before"+joinpoint.getSignature().getName()+"运行时参数表"+args );
}
@After( "pointCut()" ) //运行异常与否 都要执行的
public void logEnd(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName()+"除法结束@After");
}
@AfterReturning(value="pointCut()", returning="result")
public void logReturn(JoinPoint joinpoint,Object result ) { //result 接受返回值
System.out.println(joinpoint.getSignature().getName()+"除法正常运行@AfterReturning,结果:"+result);
}
@AfterThrowing(value = "pointCut()", throwing="e")
public void logException(JoinPoint joinpoint, Exception e) {
System.out.println( joinpoint.getSignature().getName()+"除法异常@AfterThrowing"+e.getMessage());
}
}
配置:
@EnableAspectJAutoProxy
@Configuration
public class AOPConfig {
@Bean //业务逻辑类注册到容器
public Mathcalculator mathcalculator() {
return new Mathcalculator();
} @Bean // 切面类注册到容器中
public LogAspects logAspects() {
return new LogAspects();
}
}
测试类:
public class test {
@Test
public void test01(){
//使用无参构造器 创建applicationContext (详情自己研究下有参构造器的方法)
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(AOPConfig.class);
Mathcalculator bean = applicationContext.getBean(Mathcalculator.class);
bean.div(1, 1);
//设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev","test"); //可以设置多个
//注册主配置类
applicationContext.register(Profile.class);
//启动刷新容器
applicationContext.refresh();
}
}
结果:

JointPoint 要写一定要写在 参数的首位!
三步走:
1 将业务逻辑组件和切面类都加入到容器,告诉Spring哪个是切面类(@Aspect)
2 在切面类上的每一个通知方法上标注 通知注解,告诉Spring合适何地运行(切入点表达式)
3 开启基于注解的aop模式 与config上
总结:
aop的原理
加入@EnableAspectJAutoProxy 才有AOP

继续点开看

利用AspectJAutoProxyRegistrar 给自定义容器中注册bean
给容器注册一个AnnotationAwareAspectJAutoProxyCreator 自动代理创建器
可以一直追踪其父类:

实现了 SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
后置处理器
关注后置处理器的工作 Bean初始化完成前后做的事情
BeanFactory 自动注入
AbstractAutoProxyCreator :
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
然后是与后置处理器有关的:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
有后置处理器的逻辑
AbstractAutoProxyCreator 类
AnnotationAwareAspectJAutoProxyCreator 类 initBeanFactory
启动后
1、 传入主配置类 创建 IOC容器
2、 注册配置类 调用refresh() 刷新容器
3、 registerBeanPostProcessors(beanFactory) 注册bean的后置处理器 方便拦截bean的创建
1先获取ioc容器中已经定义了需要创建对象的所有BeanPostProcessor
2给容器加别的BeanPostProcessor
3优先注册实现了PriorityOrdered接口的BeanPostProcessor
4在给容器中注册实现了Ordered接口的BeanPostProcessor
5注册没实现优先级接口的BeanPostProcessor
创建internalAutoProxyCreator的BeanPostProcessor
创建Bean的实例
populateBean 初始化Bean
1、 invokeAwareMethods() 处理Aware接口的方法回调
2、 applyBeanPostProcessorsBeforeInitialization() 应有后置处理器的BeforeInitialization( )
3、invokeInitMethods() 自定义的初始化方法
4、applyBeanPostProcessorsAfterInitialization () 执行后置处理器的 postProcessAfterInitialization
4、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功; aspectJAdvisorBuilder
6 把beanPostProcessor注册到BeanFactory中 调用addBeanPostProcessor(postProcessor)
Spring注解(AOP)的更多相关文章
- Spring注解 - AOP 面向切面编程
基本概念: AOP:Aspect Oriented Programming,即面向切面编程 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式 前置通知(@Before):在目标 ...
- 基于spring注解AOP的异常处理
一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...
- Spring注解AOP及单元测试junit(6)
2019-03-10/20:19:56 演示:将xml配置方式改为注解方式 静态以及动态代理推荐博客:https://blog.csdn.net/javazejian/article/details/ ...
- spring 注解AOP
aspectAnnotation的切面信息,加到了AnnotationAwareAspectJAutoProxyCreator的advisorsCache属性里面去了. 解析annotationSe ...
- 重新学习Spring注解——AOP
面向切面编程——思想:在一个地方定义通用功能,但是可以通过声明的方式定义这个功能要以何种方式在何处运用,而无须修改受影响的类. 切面:横切关注点可以被模块化为特殊的类. 优点: 1.每个关注点都集中在 ...
- spring注解 aop
@Resource(name="as") 为空按类型装配 @autowired 按类型 @quafiler (name="xx") 按名称 spring继承关 ...
- spring 注解aop调用invoke()
public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlAp ...
- 一步一步深入spring(5)--使用基于注解的spring实现 AOP
1.要利用spring aop,至少需要添加以下jar包 使用spring需要的jarspring.jar .commons-logging.jar 使用切面编程(AOP)需要的jar aspectj ...
- Java框架spring 学习笔记(十四):注解aop操作
回见Java框架spring Boot学习笔记(十三):aop实例操作,这里介绍注解aop操作 首先编写一个切入点HelloWorld.java package com.example.spring; ...
- Spring的AOP基于AspectJ的注解方式开发3
上上偏博客介绍了@Aspect,@Before 上篇博客介绍了spring的AOP开发的注解通知类型:@Before,@AfterThrowing,@After,@AfterReturning,@Ar ...
随机推荐
- Android无线测试之—UiAutomator UiObject API介绍四
输入文本与清除文本 一.输入文本与清除文本相关API 返回值 API 描述 boolean setText(String test) 在对象中输入文本 void clearTextField() 清除 ...
- getComputedStyle获取css属性与IE下的currentStyle获取到的值不同
<!doctype html><html lang="en"> <head> <meta charset="UTF-8&quo ...
- ETCD数据空间压缩清理
场景:做etcd数据镜像的时候出现如下错误 Error: etcdserver: mvcc: database space exceeded 通过查找官方文档https://coreos.com/e ...
- Go语言性能测试
对于一些服务来说,性能是极其重要的一环,事关系统的吞吐.访问的延迟,进而影响用户的体验. 写性能测试在Go语言中是很便捷的,go自带的标准工具链就有完善的支持,下面我们来从Go的内部和系统调用方面来详 ...
- 【Python之路】第二十三篇--Django【进阶篇】
文件配置 1.模版Templates文件配置: TEMPLATE_DIRS = ( os.path.join(BASE_DIR,'templates'), ) 2.静态文件static配置: STAT ...
- Codeblocks自动代码格式化+快捷键
Codeblocks自动代码格式化+快捷键 - u010112268的博客 - CSDN博客 https://blog.csdn.net/u010112268/article/details/8110 ...
- 码云平台, Git提交需要输入用户名/密码, 怎么办
这是因为, 检出代码的时候, 使用了http的方式: 那么, 改为ssh的地址就行了
- Python SQLAlchemy基本操作和常用技巧(包含大量实例,非常好)
https://www.jb51.net/article/49789.htm 首先说下,由于最新的 0.8 版还是开发版本,因此我使用的是 0.79 版,API 也许会有些不同.因为我是搭配 MySQ ...
- 剑指Offer——替换空格
题目描述: 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 分析: 如果从前往后替换空格,那 ...
- 洛谷 P2300 合并神犇
洛谷 听说这题可以\(n^2\)水过去,不过这里介绍一种\(O(n)\)的做法. \(f[i]\)为第\(1-i\)位合并的次数. \(pre[i]\)为第\(1-i\)位最末尾的数. \(j\)为满 ...