AOP学习
Java中,调用一个实例方法,首先得new对象,而new对象的前提是必须有对应的class字节码文件,且得通过类加载器把它加载到运行时数据区的方法区里。
① 可通过 javac xx.java 编译字节码文件;
② 可通过 ASM (一款读写Java字节码的工具)来生成字节码文件。
SpringAOP的底层是动态代理。
动态代理的底层是ASM或JDK自带的动态代理,对应着SpringAOP里提供的两种动态代理:cglib动态代理、JDK动态代理。
JDK自带的动态代理,是通过JVM内部的Native方法来实现生成字节码的。
cglib动态代理,是第三方提供的jar包,是通过ASM来实现生成字节码的。
都是用于在运行时动态的生成字节码文件。
如果目标类实现了接口,Spring会采用JDK动态代理来生成代理类的字节码,生成的代理类和目标类实现了同样的接口;如果目标类没有实现接口,Spring会采用cglib动态代理来生成字节码,生成的代理类是目标类的子类。
SpringAOP在运行时动态拼接生成class字节码,在字节码文件里,把切面类里面定义的增强方法的内容和目标类的目标方法的内容做了结合,而且可以根据你的配置去做不同方式的结合。
根据配置,可以把增强的动作结合在目标动作之前(AOP的前置通知);也可把增强的动作结合在目标动作之后(AOP后置通知);AOP还有很多通知,都可根据配置去实现。
SpringAOP拼接生成代理类的字节码后,再利用反射就生成代理类的代理对象了,然后把代理对象放入SpringIOC容器中。
相关SpringAOP名词
(1)切面类:要执行的增强方法所在的类。
(2)通知:切面类里的增强方法(比如事务的开启和提交)
(3)目标方法:目标类里要执行的目标方法。
(4)织入:把切面类的增强方法(通知)和目标方法进行结合形成代理类的过程。
(5)代理类的方法 = 通知(增强方法) + 目标方法。
AOP配置文件内容
(1)导入目标类和切面类,把目标类和切面类放入Spring容器里,交给Spring管理。
点击查看代码
<!-- 导入目标类 -->
<bean id="personService" class="com.cj.study.spring.aop.PersonServiceImpl"></bean>
<!-- 导入切面 -->
<bean id="myTransaction" class="com.cj.study.spring.aop.MyTransaction"></bean>
(2)aop:pointcut:切入点
(3)expression:切入点表达式
(用切入点和切入点表达式去告诉Spring哪些类需要生成代理类)
点击查看代码
<aop:pointcut expression="execution(* com.cj.study.spring.aop.*.*(..))" id="perform"/>
(4)aop:aspect:切面类
(5)aop:after、aop:before:通知
点击查看代码
<aop:aspect ref="myTransaction">
<aop:before method="beginTransaction" pointcut-ref="perform"/>
</aop:aspect>
<aop:aspect ref="myTransaction">
<aop:after method="commit" pointcut-ref="perform"/>
</aop:aspect>
AOP通知类型
(1)前置通知
在目标方法执行之前执行,一定会被执行。
(2)后置通知
在目标方法之后执行,当目标方法遇到异常后,后置通知将不再执行。后置通知可以接受目标方法的返回值。
(3)最终通知
在目标方法执行之后执行,无论目标方法是否抛出异常,反正一定会被执行。
(4)异常通知
接受目标方法抛出的异常信息。
(5)环绕通知
环绕通知可以控制目标方法是否执行,如果不在环绕通知中调用ProceedingJoinPoint的proceed,目标方法不会执行。
SpringAOP具体加载步骤
1、当Spring容器启动时,会加载xml配置文件。
2、Spring会为纳入Spring管理的Bean创建对象,创建对象的时候会解析apo.config配置。解析切入点表达式,将切入点表达式和纳入Spring管理的Bean作匹配。如果匹配成功,则为该Bean创建代理对象,代理对象的方法=通知+目标方法;如果匹配不成功,则为该Bean创建正常的对象,而不是代理对象。
3、使用时,用context.getBean从Spring容器中获取对象时,若该对象有代理对象则返回代理对象,没有则返回正常对象。
声明式事务
Spring的事务,之所以叫声明式事务,是因为只需要在配置文件里生命或者注解声明一下,Spring就会自动生成代理类,且会自动把开启事务这个动作拼接到你的业务方法执行之前,把提交事务拼接到业务方法执行之后,最后拼接生成代理类的字节码。
Mybatis
除了SpringAOP,很多框架也使用了动态拼接生成字节码的技术。如mybatis。
为什么mybatis只写个mapper接口和xml文件,不需要mapper实现类就可以运行起来呢?其实现逻辑大概是使用了ASM的API来做到运行时动态的拼接代理类的字节码,且动态生成的类实现了mapper接口,也结合xml文件的内容。
学习资料来自:微信公众号 聊5毛钱Java

浙公网安备 33010602011771号