spring3.x第七章 基于@AspectJ和Schema的AOP
来源:互联网 发布:node.js硬实战115 pdf 编辑:程序博客网 时间:2024/06/01 19:13
7.1 Spring对AOP的支持
我们所说的Spring AOP,它包括基于XML配置的AOP和基于@AspectJ注解的AOP,底层都是采用动态代理技术(JDK代理或CGLib代理)。
7.2 JDK5.0注解知识快速进阶
7.2.1 了解注解
JDK5.0注解,通过Java语言的反射机制获取类中标注的注解,完成特定的功能。
注解是代码的附属信息,它遵循一个基本原则:注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。第三方工具可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑,而这正是Spring AOP对@AspectJ提供支持所采取的方法。
7.2.2 一个简单的注解类
package com.baobaotao.aspectj.anno;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) //声明注解的保留期限@Target(ElementType.METHOD) //声明可以使用该注解的目标类型public @interface NeedTest { //定义注解 boolean value() default true; //声明注解成员}
7.2.3 使用注解
package com.baobaotao.aspectj.anno;public class ForumService { @NeedTest(value=true) public void deleteForum(int forumId){ System.out.println("删除论坛模块:"+forumId); } @NeedTest(value=false) public void deleteTopic(int postId){ System.out.println("删除论坛主题:"+postId); }}
7.2.4 访问注解
通过反射获取注解信息,并进行逻辑处理。注意RUNTIME的生存期,所以JVM才会有这个注解信息。
package com.baobaotao.aspectj.anno;import java.lang.reflect.Method;public class TestTool { public static void main(String[] args) { Class clazz = ForumService.class; Method[] methods = clazz.getDeclaredMethods(); System.out.println(methods.length); for (Method method : methods) { NeedTest nt = method.getAnnotation(NeedTest.class); if (nt != null) { if (nt.value()) { System.out.println(method.getName() + "()需要测试"); }else{ System.out.println(method.getName()+"()不需要测试"); } } } }}
7.3 着手使用@AspectJ
7.3.1 使用前的准备
aspect.weaver包。
7.3.2 一个简单的例子
package com.baobaotao.aspectj.aspectj;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspect //通过注解标识为一个切面public class PreGreetingAspect { @Before("execution(* greetTo(..))“) //定义切点和增强类型,greetTo方法可以带任意的入参和任意的返回值 public void beforeGreeting(){ System.out.println("How are you"); }}
7.3.3 如何通过配置使用@AspectJ切面
<!-- 目标Bean --> <bean id="waiter" class="com.baobaotao.NaiveWaiter" /> <!-- 使用了@AspectJ注解的切面类 --> <bean class="com.baobaotao.aspectj.aspectj.PreGreetingAspectj" /> <!-- 自动代理创建器,自动将@AspectJ注解切面类织入到目标Bean中 --> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
自动代理创建器,能够将@AspectJ注解切面的自动织入到目标Bean中。
如果使用基于Schema的aop命名空间进行配置,事情就更简单了:
<aop:aspectj-autoproxy /> <bean id="waiter" class="com.baobaotao.NaiveWaiter" /> <bean class="com.baobaotao.aspectj.aspectj.PreGreetingAspect" />
7.4 @AspectJ语法基础
7.4.1 切点表达式函数
execution()
方法匹配模式串,表示满足某一匹配模式的所有目标类连接点。如exectution(* greetTo(..))
表示所有目标类中的greetTo()方法
7.4.2 在函数入参中使用通配符
*:匹配任意字符,只能匹配上下文中的一个元素
..:匹配任意字符,可以匹配上下文中的多个元素
+:匹配指定类的所有类,跟在类名后面
7.4.3 逻辑运算符
与操作符,&&,由于&是XML的特殊字符,使用and
或操作符,||、or
非操作符,!、not
7.4.4 不同增强类型
@Before,前置增强
@AfterReturning,后置增强
@Around,环绕增强
@AfterThrowing,抛出增强
@After,Fianl增强。一般用于释放资源
@DeclarParents,引介增强
7.4.5 引介增强用法
希望NaiveWaiter能够同时充当售货员的角色,即通过切面结束为NaiveWaiter新增Seller接口的实现。
package com.baobaotao.aspectj.basic;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.DeclareParents;import com.baobaotao.Seller;import com.baobaotao.SmartSeller;@Aspectpublic class EnableSellerAspect { @DeclareParents(value="com.baobaotao.NaiveWaiter", defaultImpl=SmartSeller.class) public Seller seller;}
<aop:aspectj-autoproxy /> <bean id="waiter" class="com.baobaotao.NaiveWaiter" /> <bean class="com.baobaotao.aspectj.basic.EnableSellerAspect" />
package com.baobaotao.aspectj.example;import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.baobaotao.NaiveWaiter;import com.baobaotao.Seller;import com.baobaotao.Waiter;import com.baobaotao.aspectj.aspectj.PreGreetingAspect;public class DeclaredParentsTest { public static void main(String[] args) { String path = "com/baobaotao/aspectj/basic/AspectJBean.xml"; ApplicationContext act = new ClassPathXmlApplicationContext(path); Waiter waiter = act.getBean("waiter", Waiter.class); waiter.greetTo("John"); Seller seller = (Seller) waiter; seller.sell("Beer", "John"); }}
7.5 切点函数详解
7.5.1 @annotation()
出错:error the @annotation pointcut expression is only supported at Java 5 compliance level or above。
7.5.2 execution()
其语法:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
通过方法签名定义切点
execution(public (..)):第一个代表返回类型,第二个*代表方法名;而..代表任意入参。匹配所有目标类的public方法。
execution( To(..)):第一个代表返回类型,*To代表任意以To为后缀的方法。
通过类定义切点
execution(* com.baobaotao.Waiter.(..)):第一个代表返回任意类型。匹配Waiter接口中的所有方法。
execution(* com.baobaotao.Waiter+.*(..)):匹配Waiter接口及其所有实现类的方法。
通过类包定义切点
execution(* com.baobaotao.*(..)):匹配包下的所有类的所有方法
execution(* com.baobaotao..*(..)):匹配包、子孙包下所有类的所有方法。
execution(* com...*Dao.find(..)):匹配包名前缀为com,后缀为Dao的方法,方法名必须以find为前缀。
通过方法入参定义切点
execution(* joke(String, int)):匹配joke(String,int)方法
execution(* joke(String, int)):匹配joke(String,*)方法,第二个参数都行。
execution(* joke(String, …)):匹配joke(String,多个参数)。
execution(* joke(Object+)):匹配一个入参,且这个入参是Object类型或该类的子类。
7.5.3 args()和@args()
args(com.baobaotao.Waiter):匹配参数是Waiter类或其子类。
7.5.4 within()
最小匹配的单位是类。with(com.baobaotao.*)匹配子类,不包括子孙类。
7.5.5 @within()和@target()
如果@within(M),M注解的是一个接口,而其子类没有M注解,则不能对子类进行定义切点,因为其都是针对目标类而言,而非针对运行时的引用类型而言。@target()、@annotation()也是。
7.5.6 target()的this()
7.6 @AspectJ进阶
7.6.1 切点复合运算
package com.baobaotao.aspectj.advanced;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class TestApsect { @After("within(com.baobaotao.*) && execution(* greetTo(..))") public void greeToFun(){ System.out.println("--greeToFun() executed!--"); } @Before("!target(com.baobaotao.NaiveWaiter) && execution(* serveTo(..))") public void notServeInNaiveWaiter(){ System.out.println("--notServeInNaiveWaiter() executed!--"); } @AfterReturning("target(com.baobaotao.Waiter) || target(com.baobaotao.Seller)") public void waiterOrSeller(){ System.out.println("--waiterOrSeller() executed!--"); }}
7.6.2 命名切点
package com.baobaotao.aspectj.advanced;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class TestAspect { @Before("TestNamePointcut.inPkgGreetTo()") public void pkgGreetTo(){ System.out.println("--pkgGreetTo() executed!--"); } @Before("!target(com.baobaotao.NaiveWaiter) && TestNamePointcut.inPkgGreetTo()") public void pkgGreetToNotNaiveWaiter(){ System.out.println("--pkgGreetToNotNaiveWaiter() executed!--"); }}
7.6.3 增强织入的顺序
7.6.4 访问连接点信息
7.6.5 绑定连接点方法入参
7.6.6 绑定代理对象
7.6.7 绑定类注解对象
7.6.8 绑定返回值
7.6.9 绑定抛出的异常
7.7 基于Schema配置切面
7.7.1 一个简单切面的配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:before pointcut="target(com.baobaotao.NaiveWaiter) and execution(* greetTo(..))" method="preGreeting"/> </aop:aspect> </aop:config> <bean id="adviceMethods" class="com.baobaotao.schema.AdviceMethods" /> <bean id="naiveWaiter" class="com.baobaotao.NaiveWaiter" /> <bean id="naughtyWaiter" class="com.baobaotao.NaughtyWaiter" /></beans>
package com.baobaotao.schema;public class AdviceMethods { public void preGreeting(){ System.out.println("--how are you!--"); }}
7.7.2 配置命名切点
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:pointcut id="greetToPointcut" expression="target(com.baobaotao.NaiveWaiter) and execution(* greetTo(..))" /> <aop:before pointcut="" method="preGreeting" pointcut-ref="greetToPointcut"/> </aop:aspect> </aop:config>
7.7.3 各种增强类型的配置
后置增强
<aop:config proxy-target-class="true"> <aop:aspect ref="adviceMethods"> <aop:after-returning method="afterReturning" pointcut="target(com.baobaotao.SmartSeller)" returning="retVal" /> </aop:aspect></aop:config>
public class AdviceMethods{ public void afterReturning(int retVal){ }}
环绕增强
<aop:around method="aroundMethod" pointcut="target(com.baobaotao.SmartSeller)" />
public class AdviceMethods{ public void aroundMethod(int retVal){ }}
抛出异常增强
<aop:after-throwing method="afterThrowingMethod" pointcut="target(com.baobaotao.SmartSeller)" throwing="iae"/>
public class AdviceMethods{ public void afterThroingMethod(IllegalArgumentException iae){ }}
Fianl增强
<aop:after method="afterMethod" pointcut="target(com.baobaotao.SmartSeller)" />
引介增强
<aop:declare-parents implement-interface="com.baobaotao.Seller" default-impl="com.baobaotao.SmartSeller" types-matching="com.baobaotao.Waiter+" />
7.7.4 绑定连接点信息
7.7.5 Advisor配置
Advisor是Spring中切面概念的对应物,是切点和增强的复合体不过仅包含一个切点和一个增强。
<aop:config> <aop:advisor advice-ref="testAdvice" pointcut="execution"/></aop:config><bean id="testAdvice" class=""/>
7.8 混合切面类型
4种定义切面的方式
基于@AspectJ注解的方式;
基于<aop:aspect>
的方式;
基于<aop:advisor>
;
基于Advisor类的方式;
7.8.2 各种切面类型总结
7.9 JVM Class文件字节码转换基础知识
到目前为止,我们所接触到的AOP切面织入都是在运行期通过JDK代理或CGLib代理的方式实现的。还可以在类加载期通过字节码编辑的技术,将切面织入到目标类中,这种织入方式称为LTW(Load Time Weaving)。
7.9.1 java.lang.instrument包的工作原理
该包中有两个能对JVM底层组件进行访问的类
7.9.2 如何向JVM中注册转换器
7.9.3 使用JVM启动参数注册转换器的问题
7.10 使用LTW织入切面
7.10.1 Spring的LoadTimeWeaver
7.10.2 使用LTW织入一个切面
7.10.3 在Tomcat下的配置
7.10.4 在其他Web应用服务器下的配置
7.11 小结
许多都通过AOP进而伸展到更加深入,偏原理底层的知识。
JDK5.0的注解知识,是学习@AspectJ的基础。
掌握切点表达式语法和切点函数是学习@Aspect的重心。
基于Schema配置的方式继续使用AspectJ的切点表达式和增强定义,基于Schema的配置采用描述@Aspect类所描述的相同信息,知识换一种方法而已。还可以通过复用旧系统已有的Advice并配合使用Aspect的切点表达式。
Spring还支持LTW的功能,允许通过AspectJ定义切面,在类加载期通过类文件转换器织入切面。
- spring3.x第七章 基于@AspectJ和Schema的AOP
- 6.基于@AspectJ和Schema的AOP
- 基于@AspectJ和Schema的AOP(精通Spring+4.x++企业应用开发实战 第八章)
- 小曹学spring--基于@AspectJ和Schema的AOP
- Spring4学习:基于@AspectJ和Schema的AOP
- Spring AOP的实现机制(三)---@AspectJ形式的Spring AOP和基于Schema的AOP
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我学spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我学spring3
- Jenkins-Requeue Job
- asch相关的linux基础知识分享
- iOS10里的通知与推送
- SOA架构
- Android之scrollview底部继续拖动查看图文详情
- spring3.x第七章 基于@AspectJ和Schema的AOP
- range()函数用法
- Dynamics 365 for Sales:轻松搭建自己的企业门户
- 51nod 1781 Pinball
- Java中对象的上转型对象
- Two pointers
- python-add character on image
- C++ 转向语句:break continue goto return
- 关于启动vue+node.js项目报错的解决