重新学习Spring2——IOC和AOP原理彻底搞懂
一、AOP
1 Spring AOP 的实现原理
是对OOP编程方式的一种补充。翻译过来为“面向切面编程”。
1 AspectJ是静态代理的增强:所谓静态代理就是AOP框架会在便一阶段生成AOP代理类,也叫编译器增强。
2 使用Spring AOP
- 与AspectJ 的静态代理不同,Spring AOP使用的是动态代理,动态代理指AOP框架不会去修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并在特定的切点做了增强处理,并回调原对象的方法。
- Spring AOP中的动态代理有两种:JDK动态代理(代理必须实现一个接口)、CGLIB动态代理(代理可以不实现接口)
- 几个概念:
- 切面(Advisor):是AOP中的一个术语,表示从业务逻辑中分离出来的横切逻辑,比如性能监控、日志处理、权限控制等。
这些功能都可以从核心的业务逻辑中抽离出去。可以解决代码耦合的问题,职责更加单一。封装了增强和切点。 - 增强(Advice):增强代码的功能的类,横切到代码中。
- 目标:目标方法(JDK代理)或目标类(CGLIB代理)。
- 代理:通过ProxyFactory类生成,分为JDK代理、CGLIB代理。
- 切点:通过一个条件来匹配拦截的类,这个条件成为切点。
- 连接点:作为增强方法的入参,可以获取目标方法的信息。
- 切面(Advisor):是AOP中的一个术语,表示从业务逻辑中分离出来的横切逻辑,比如性能监控、日志处理、权限控制等。
- 增强
- 织入(Weaving):将切面应用到目标对象并导致代理对象创建的过程。
- 1 前置增强(Before):在目标方法前调用。
- 2 后置增强(AfterAdvice):在目标方法后调用。
- 3 环绕增强(AroundAdvice):将Before和After,甚至抛出增强和返回增强合到一起。
- 4 返回增强(AfterReturningAdvice):在方法返回结果后执行,该增强可以接收到目标方法返回的结果。
- 5 抛出增强(AfterThrowingAdvice):在目标方法抛出对应的类型后执行,可以接收到对应的异常信息。
- 引入增强(DeclareParentsAdvice):想让程序在运行的时候动态实现某个接口,需要引入增强。
- 织入(Weaving):将切面应用到目标对象并导致代理对象创建的过程。
3 注解:Spring + AspectJ
- 1 对切面类添加 @Aspect 注解;将切面类和目标类放入到IOC容器中,可以通过
<context:component-scan base-package=""/>进行扫描。 - 2 添加增强方法(包括增强类型和切点表达式,以及连接点)。
- 3 在Spring 配置文件中添加
<aop:aspectj-autoproxy proxy-target-class="true"/>,false表示只能代理接口(JDK动态代理),true表示代理类(CGLIB代理)。 3.1 通过切点表达式(AspectJ execution)进行拦截
- 步骤一:配置pox.xml:
- 1 对切面类添加 @Aspect 注解;将切面类和目标类放入到IOC容器中,可以通过
<!--Spring AOP依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
- 步骤二:spring-config.xml
<!-- 注解扫描-->
<context:component-scan base-package="com.sean.aoptest"></context:component-scan>
<!-- 设置aop动态代理类型:true为代理类,false为代理接口 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
- 步骤三:编写代码,在这里我上传一段测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring-config-test.xml"})
public class SpringTest{
@Autowired
private Student student;
@Test
public void test01(){
System.out.println(student.say("zengxing"));
}
}
@Component
class Student implements Person{
@Override
public String say(String name) {
// TODO Auto-generated method stub
// if (name.equals("zengxing")) {
// throw new RuntimeException("名字不能是" + name); //要抛出运行时异常
// }
return "Hello, " + name;
}
}///*
around before...
before
around after...
after
str:Hello, zengxing
afterReturningAdvice
Hello, zengxing
*///
@Aspect
@Component
class LoggingAspect{
//前置
@Before("execution(String say(String))")
public void before(JoinPoint point){
System.out.println("before");
}
//后置
@After("execution(String say(String))")
public void after(JoinPoint point){
System.out.println("after");
}
//环绕
@Around("execution(String say(String))")
public Object around(ProceedingJoinPoint point) throws Throwable{
System.out.println("around before...");
Object result = point.proceed();
System.out.println("around after...");
return result;
}
//返回
@AfterReturning(value="execution(String say(String))", returning="str")
public void afterReturningAdvice(JoinPoint point, String str){
System.out.println("str:" + str);
System.out.println("afterReturningAdvice");
}
//抛出
@AfterThrowing(value = "execution(String say(String))", throwing = "e")
public void afterThrowingAdvice(JoinPoint point, Exception e){
String message = e.getMessage();
System.out.println(message);
System.out.println("AfterThrowingAdvice...");
}
}
3.2 通过切点注解表达式(AspectJ @annotation)进行拦截
- 开发步骤:
- 1 定义注解类
- 开发步骤:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface AuthorityTag { }
- 2 为切面类中增强指定注解表达式
@Aspect
@Component
class AuthorityAspect{
@Before("@annotation(com.sean.aoptest.AuthorityTag)")
public void before(JoinPoint point){
System.out.println("authority before");
}
}
- 3 在目标类目标方法上标注注解
@Component //将对象放入到IOC容器中
class Car1 implements Wheel{
@AuthorityTag //标注切入的的增强
@Override
public void run(){
System.out.println("I am a car, i can run");
}
}
4 小的知识点
- 利用方法签名编写 AspectJ 切点表达式
- execution * com.sean.Calculator.* (…):匹配Calculator中声明的所有方法,
第一个 * 代表任意修饰符及任意返回值。第二个 * 代表任意方法。…匹配任意数量的参数。若目标类与接口与该切面在同一个包中,可以省略包名。 - execution public * Calculator.*(…):匹配ArithmeticCalculator 接口的所有公有方法。
- execution public double Calculator.*(…):匹配Calculator中返回double类型数值的方法。
- execution public double Calculator.*(double, …):匹配第一个参数为double类型的方法,…匹配任意数量任意类型的参数。
- execution public double Calculator.*(double, double):匹配参数类型为double,double类型的方法。
- execution * com.sean.Calculator.* (…):匹配Calculator中声明的所有方法,
- 可以结合切点表达式使用 &&, ||, ! 来合并。如:
- execution(void run()) || execution(void say())
- 切面优先级:
- 可以通过实现Ordered接口或利用@Order注解指定。
- 1 实现Ordered接口,getOrder()方法返回的值越小,优先级越高。
- 2 使用@Order注解,需要出现在注解中,同样是值越小优先级越高。
- 利用方法签名编写 AspectJ 切点表达式
参考博客:https://blog.csdn.net/qq_16605855/article/details/73465865
重新学习Spring2——IOC和AOP原理彻底搞懂的更多相关文章
- 170511、Spring IOC和AOP 原理彻底搞懂
Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口.抽象类.或工具类的形式存在于Spring中.通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合.比如有关jdbc ...
- spring的ioc与aop原理
ioc(反向控制) 原理: 在编码阶段,既没有实例化对象,也没有设置依赖关系,而把它交给Spring,由Spring在运行阶段实例化.组装对象.这种做法颠覆了传统的写代码实例化.组装对象.然后一 ...
- Spring源码学习之IOC容器实现原理(一)-DefaultListableBeanFactory
从这个继承体系结构图来看,我们可以发现DefaultListableBeanFactory是第一个非抽象类,非接口类.实际IOC容器.所以这篇博客以DefaultListableBeanFactory ...
- Java轻量级业务层框架Spring两大核心IOC和AOP原理
IoC(Inversion of Control): IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些 ...
- spring框架DI(IOC)和AOP 原理及方案
http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html http://www.oschina.net/code/snippe ...
- Spring学习笔记IOC与AOP实例
Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...
- spring中IOC和AOP原理
IoC(Inversion of Control): (1)IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中转 ...
- Spring基础篇——DI/IOC和AOP原理初识
DI(Dependency Injection),依赖注入,和我们常听说的另一个概念 IOC(控制反转)其实归根结底实现的功能是相同的,只是同样的功能站在不同的角度来阐述罢了.这里博主就不去过多的辨析 ...
- Spring核心 IoC和AOP原理
1. 什么是Spring Spring是一个轻量的Java开源框架,它简化了应用开发,实现基于POJO的编程模型.它的两大核心是:IoC(控制反转),AOP(面向切面编程). 2. IoC控制反转 简 ...
随机推荐
- mvn常见参数命令讲解
关于-N -N,--non-recursive Do not recurse into sub-projects 意思是,不递归到子项目(子模块). 举例: 一个父项目下Father面有3个子项目A. ...
- Shared variable in python's multiprocessing
Shared variable in python's multiprocessing https://www.programcreek.com/python/example/58176/multip ...
- odoo开发笔记 -- 借助模块queue_job实现异步方法调用
场景描述: 对比了几个定时调度的框架,发现各有优缺点: celery 很强,异步定时调度,异步周期调度,也有延时调度的功能,但是延时调度的案例比较少,遂暂时不使用. queue_job,一个odoo第 ...
- redhat 6安装python 3.7.4报错ModuleNotFoundError: No module named '_ctypes' make: *** [install] Error 1
问题描述: 今天在测试环境中,为了执行脚本,安装下python3命令,在执行make install的时候报错: ModuleNotFoundError: No module named '_ctyp ...
- Java12新特性 -- 可中断的 G1 Mixed GC
G1是一个垃圾收集器,设计用于具有大量内存的多处理器机器.由于它提高了性能效率,G1垃圾收集器最终将取代CMS垃圾收集器. 该垃圾收集器设计的主要目标之一是满足用户设置的预期的 JVM 停顿时间. G ...
- 011-Spring aop 002-核心说明-切点PointCut、通知Advice、切面Advisor
一.概述 切点Pointcut,切点代表了一个关于目标函数的过滤规则,后续的通知是基于切点来跟目标函数关联起来的. 然后要围绕该切点定义一系列的通知Advice,如@Before.@After.@Af ...
- BigDecimal 与double 转化失真
1.BigDecimal(double val): 失真, 不要使用 BigDecimal(0.1)的值是: 0.1000000000000000055511151231257827021181583 ...
- 百度网盘快速下载工具下载:Pandownload下载
众所周知的百度网盘下载限速很厉害,所以就有了快速下载工具出现了.一般情况下,按照家里网速有多快,使用工具下载就有多快. 可以直接复制如下图进行下载: 另外,PanDownload[百度网盘下载工具]无 ...
- [ERROR] ionic-app-scripts has unexpectedly closed (exit code 1).
这个错误是因为缺失 '@ionic/app-scripts',只要安装 '@ionic/app-scripts' 即可. 解决方法:npm install @ionic/app-scripts@lat ...
- 多用户同时操作一条Mysql记录问题
场景:两个用户同时读取了数据库中的一条记录,此时用户A对其中一个字段的值进行了修改操作并进行了提交,后来用户B也对这个字段进行了修改,用户B的提交将会覆盖用户A提交的值 关于乐观锁和悲观锁 悲观锁:每 ...