Spring的AspectJ的AOP
AspectJ 是一个面向切面的框架,它扩展了 Java 语言。 AspectJ 定义了 AOP 语法所以它有一个专门的编译器用来生成遵守 Java 字节编码规范的 Class 文件。
AspectJ 是一个基于 Java 语言的 AOP 框架,Spring2.0 以后新增了对 AspectJ 切点表达式支持
@AspectJ 是 AspectJ1.5 新增功能,通过 JDK5 注解技术,允许直接在 Bean 类中定义切面
新版本 Spring 框架,建议使用 AspectJ 方式来开发 AOP。
在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"。
execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)
除了返回类型模式、方法名模式和参数模式外,其它项都是可选的
实例:
1 2 3 4 5 6 7 8 9 10 11 |
execution (* com.sample.service.impl..*.*(..)) 整个表达式可以分为五个部分: 1 、execution(): 表达式主体。 2 、第一个*号:表示返回类型,*号表示所有的类型。 3 、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。 4 、第二个*号:表示类名,*号表示所有的类。 5 、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。 execution(“* cn.spring3.demo1.dao.*(..)”) --- 只匹配当前包 execution(“* cn.spring3.demo1.dao..*(..)”) --- 匹配包及当前包的子包 . execution(* cn.dao.GenericDAO+.*(..)) --- 匹配 GenericDAO 及子类<br>execution(* save*(..)) ---匹配所有save开头的方法 |
@Before 前置通知,相当于 BeforeAdvice
@AfterReturning 后置通知,相当于 AfterReturningAdvice
@Around 环绕通知,相当于 MethodInterceptor
@AfterThrowing 抛出通知,相当于 ThrowAdvice
@After 最终 final 通知,不管是否异常,该通知都会执行
@DeclareParents 引介通知,相当于 IntroductionInterceptor
一、基于注解的方式
开发步骤:
- 第一步 : 引入相应 jar 包
* aspectj 依赖 aop 环境 .
* spring-aspects-3.2.0.RELEASE.jar
* com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
- 第二步 : 编写目标类
- 第三步 : 使用AspectJ注解自定义切面类,就是切点与增强结合
- 第四步 : 配置XML
* 引入 aop 的约束 :
* <aop:aspectj-autoproxy /> --- 自动生成代理 :
* 底层就是 AnnotationAwareAspectJAutoProxyCreator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// 类 public class Student {
public void add(){
System.out.println( "添加方法..." ); } public void delete(){
System.out.println( "删除方法..." ); } } // 切面 @Aspect public class MyAspect {
@Before ( "execution(* spring2..*.add*(..))" ) void before(){
System.out.println( "前置增强..." ); } } // 测试 @RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration ( "classpath:config3.xml" ) public class Demo {
@Resource (name = "stu" ) private Student s; @Test public void demo(){
s.add(); } } |
配置XML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?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:aop= "http://www.springframework.org/schema/aop" xsi:schemaLocation=" http: //www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http: //www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--自动生成代理,底层就是 AnnotationAwareAspectJAutoProxyCreator--> <aop:aspectj-autoproxy/> <bean id= "stu" class = "spring2.Student" /> <!--需要把切面类进行注册,才能自动生成代理--> <bean id= "myaspect" class = "spring2.MyAspect" /> </beans> |
* 其他的增强的使用:
AspectJ的通知类型:
@Before 前置通知,相当于BeforeAdvice
* 就在方法之前执行.没有办法阻止目标方法执行的.
@AfterReturning 后置通知,相当于AfterReturningAdvice
* 后置通知,获得方法返回值.
@Around 环绕通知,相当于MethodInterceptor
* 在可以方法之前和之后来执行的,而且可以阻止目标方法的执行.
@AfterThrowing 抛出通知,相当于ThrowAdvice
@After 最终final通知,不管是否异常,该通知都会执行
@DeclareParents 引介通知,相当于IntroductionInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
@Aspect public class MyAspect {
@Before ( "execution(* spring2..*.add*(..))" ) void before() {
System.out.println( "前置增强..." ); } @AfterReturning (value = "execution(* spring2..*.add*(..))" , returning = "returnVal" ) public void afterReturning(Object returnVal) {
System.out.println( "后置增强..." + "方法的返回值:" + returnVal); } @Around ( "execution(* spring2..*.add*(..))" ) public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println( "环绕前增强..." ); Object object = proceedingJoinPoint.proceed(); System.out.println( "环绕后增强..." ); return object; } @AfterThrowing (value = "execution(* spring2..*.add*(..))" , throwing = "e" ) public void throwing(Throwable e) {
System.out.println( "不好,出异常了!" + e.getMessage()); } @After ( "execution(* spring2..*.add*(..))" ) public void after() {
System.out.println( "最终通知..." ); } } |
* 基于AspectJ的切点定义
使用 @Pointcut 进行自定义的切点定义。
1 2 3 4 5 6 7 8 9 10 |
@Aspect public class MyAspect {
@Before ( "MyAspect.myPointcut()" ) void before() {
System.out.println( "前置增强..." ); } @Pointcut ( "execution(* spring2..*.add*(..))" ) private void myPointcut(){} } |
* Advisor和Aspect的区别
Advisor:Spring传统意义上的切面:支持一个切点和一个通知的组合.
Aspect:可以支持多个切点和多个通知的组合.
二、基于XML的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * 切面类 */ public class MyAspectXML {
public void before() {
System.out.println( "前置通知..." ); } public void afterReturing(Object returnVal) {
System.out.println( "后置通知...返回值:" + returnVal); } public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println( "环绕前增强...." ); Object result = proceedingJoinPoint.proceed(); System.out.println( "环绕后增强...." ); return result; } public void afterThrowing(Throwable e) {
System.out.println( "异常通知..." + e.getMessage()); } public void after() {
System.out.println( "最终通知...." ); } } |
XML配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<!-- 定义切面 --> <bean id= "myAspect" class = "spring2.MyAspect" ></bean> <!-- 定义aop配置 --> <aop:config> <!-- 定义切点: --> <aop:pointcut expression= "execution(* cn.itcast.spring3.demo2.ProductDao.add(..))" id= "mypointcut" /> <aop:aspect ref= "myAspect" > <!-- 前置通知 --> <!-- <aop:before method= "before" pointcut-ref= "mypointcut" /> --> <!-- 后置通知 --> <!-- < aop:after -returning method= "afterReturing" pointcut-ref= "mypointcut" returning= "returnVal" /> --> <!-- 环绕通知 --> <!-- < aop:around method= "around" pointcut-ref= "mypointcut" /> --> <!-- 异常通知 --> <!-- < aop:after-throwing method= "afterThrowing" pointcut-ref= "mypointcut" throwing= "e" /> --> <!-- 最终通知 --> <aop:after method= "after" pointcut-ref= "mypointcut" /> </aop:aspect> </aop:config> |
原文 : https://www.cnblogs.com/TIMHY/p/7816812.html