两种方式开发AspectJ
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两种方式开发AspectJ相关的知识,希望对你有一定的参考价值。
两种方式开发AspectJ
AspectJ一个基于Java语言的AOP框架,建议开发者使用AspectJ实现AOP
-
使用AspectJ实现AOP有两种方式
-
1-基于XML配置开发AspectJ
-
2-基于注解开发AspectJ
-
基于XML配置开发AspectJ是指通过XML配置文件定义切面,切入点及通知
-
所有这些定义都必须在aop:config元素内,
-
aop:config:开发AspectJ顶层配置元素,配置文件beans下可以包含多个该元素
-
<aop:aspect>:配置一个切面,属性ref指定切面的定义
-
aop:pointcut:配置切入点,属性expression指定通知增强哪些方法
-
aop:before:配置前通知,属性method指定前置通知的方法,属性pointcut-ref指定关联的切入点
-
aop:after-returning:配置后置返回通知,属性method指定后置返回通知方法,属性pointcut-ref指定关联的切入点
-
aop:around:配置环绕通知,method指定环绕通知方法,属性pointcut-ref指定关联的切入点
-
aop:after-throwing:配置异常通知,属性method指定异常通知的方法,属性pointcut-ref指定关联的切入点,没有异常发生的时候将不再执行
-
aop:after:配置后置通知,属性method指定后置通知方法,属性pointcut-ref指定关联的切入点
下面通过一个实例演示基于XML配置开发AspectJ的过程
1-创建web应用ch17,并导入相关jar包如下:
2-在ch17中的src目录下创建aspectj.xml包,并在该包中创建切面类MyAspect,在该类中编写各种类型的通知。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//通过一个实例演示基于XML配置开发AspectJ的过程
public class MyAspect { //切面类,在此类中编写各种类型的通知
//前置通知,使用JoinPoint接口作为参数信息获取目标对象信息
public void before(JoinPoint joinPoint){
System.out.print("前置通知,模拟权限管理") ;
System.out.println(",目标对象:" + joinPoint.getTarget() + ",被增强处理的方法:" + joinPoint.getSignature().getName()) ;
}
//后置返回通知
public void afterReturning(JoinPoint joinPoint){
System.out.print("后置返回通知:" + "模拟删除临时文件") ;
System.out.println(",被增强处理的方法:" + joinPoint.getSignature().getName()) ;
}
//环绕通知
public Object around (ProceedingJoinPoint pjp) throws Throwable{
//开始
System.out.println("环绕开始:执行目标方法,模拟开启事务") ;
//执行当前目标方法
Object object = pjp.proceed() ;
//结束
System.out.println("环绕结束:执行目标方法后,模拟关闭事务");
return object ;
}
//异常通知
public void except(Throwable e){
System.out.println("异常通知:" + "程序执行异常" + e.getMessage()) ;
}
//后置通知,即最终通知
public void after(){
System.out.println("最终通知:模拟释放资源") ;
}
}
3-创建配置文件,并编写相关配置,在配置文件spring-config.xml中配置,为aop:config元素及其子元素编写相关配置,在配置文件中expression="execution(* dynamic.jdk..(…))"是定义切入点表达式,该切入点表达式的意思是匹配dynamic.jdk包中任意类任意方法的执行,其中第一个号代表所有类型,dynamic.jdk表示需要匹配的包名,第二个号表示类名,代表匹配包中所有的类,第三个代表方法名,使用表示的所有方法,后面的(…)表示方法的参数是任意参数
注意:第一个*号与包名dynamic.jdk之间有一个空格
<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--定义目标对象-->
<bean id = "testDao" class = "dynamic.jdk.TestDaoImpl"/>
<!--定义切面-->
<bean id = "MyAspect" class = "aspectj.xml.MyAspect"/>
<!--AOP配置-->
<aop:config>
<!--配置切面-->
<aop:aspect ref = "MyAspect">
<!--配置切入点,通知增强哪些方法-->
<aop:pointcut expression="execution(* dynamic.jdk.*.*(..))" id = "myPointCut"/>
<!--将通知与切入点关联-->
<!--关联前置通知-->
<aop:before method = "before" pointcut-ref = "myPointCut"/>
<!--关联后置返回通知-->
<aop:after-returning method="afterReturning" pointcut-ref="myPointCut"/>
<!--关联环绕通知-->
<aop:around method = "around" pointcut-ref = "myPointCut"/>
<!--关联异常通知,没有发生异常不会执行增强,throwing属性设置通知的第一个参数名称-->
<aop:after-throwing method="except" pointcut-ref="myPointCut" throwing = "e" />
<!--管理后置通知,不管目标方法师傅成功都要执行-->
<aop:after method = "after" pointcut-ref = "myPointCut"/>
</aop:aspect>
</aop:config>
</beans>
4-创建测试类,在aspectj.xml包中创建测试类XMLAspectJTest,在主方法中,使用Spring容器获取增强后的目标对象,并执行目标方法。
import dynamic.jdk.TestDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class XMLAspectJTest {
public static void main(String[] args){
//初始化Spring容器,加载配置文件
ApplicationContext appCon = new ClassPathXmlApplicationContext("spring-config.xml") ;
//从容器中获取增强后的目标对象
TestDao testDaoAdvice = (TestDao) appCon.getBean("testDao");
//执行方法
testDaoAdvice.save() ;
System.out.println("===============") ;
testDaoAdvice.modify() ;
System.out.println("===============") ;
testDaoAdvice.delete() ;
}
}
5-测试结果如下:
6-若在dynamic.jdk包的TestImpl类的save方法总添加异常代码,例如:int n = 100 / 0 ;
然后重新运行测试类,测试结果如下:
基于注解开发AspectJ要比基于XML配置开发AspectJ要便捷许多,
- 所以实际开发中往往使用注解开发AspectJ
- AspectJ注解如下:
- 1-@Aspect:用于定义一个切面,注解在切面类上
- 2-@Pointcut:用于定义切入点表达式,在使用时候需要定义一个切入点方法,该方法是一个返回值void且方法体为空的普通方法
- 3-@Before:用于定义前置通知,在使用时候通常需要指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
- 4-@AfterReturning:用于定义后置返回通知,在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义的切入点表达式
- 5-@Around:用于定义环绕通知,在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
- 6-@AfterThrowing:用于定义异常通知,在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
- 另外,还有一个throwing属性 用于访问目标方法抛出的异常,该属性值与异常通知方法中同名的形参一致。
- 7-@After:用于定义后置通知,在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式
1-在src目录下创建aspectj.annotation包,并在该包中创建切面类MyAspect, 在该类中首先使用@Aspect注解定义一个切面类,由于该类在Spring中作为组件使用的,所以还需要使用@Component注解,然后使用@Pointcut注解切入点表达式,并通过定义该方法来表示切入点名称,最后在每个通知方法上添加相应的注解,并将切入点名称作为参数传递给需要执行增强通知的方法。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect //对应<aop:aspect ref = "myAspect>
@Component //对应<bean id = "myAspect" class = "aspectj.xml.MyAspect"/>
public class MyAspect { //切面类,在该类中编写各种类型的通知
//定义切入点
@Pointcut("execution(* dynamic.jdk.*.*(..))")
private void myPointCut(){
}
//前置通知,使用JoinPoint接口作为参数获取目标对象信息
@Before("myPointCut()")
public void before(JoinPoint joinPoint){
System.out.print("前置通知:模拟权限控制") ;
System.out.println(",目标类对象:" + joinPoint.getTarget() + ",被增强处理的方法:" + joinPoint.getSignature().getName()) ;
}
//后置返回通知
@AfterReturning("myPointCut()")
public void afterReturning(JoinPoint joinPoint){
System.out.print("后置返回通知:模拟删除临时文件") ;
System.out.println(",被增强处理的方法:" + joinPoint.getSignature().getName()) ;
}
//环绕通知
@Around("myPointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
//开始
System.out.println("环绕开始:执行目标方法前,模拟开启事务") ;
//执行当前目标方法
Object object = pjp.proceed() ;
System.out.println("环绕结束:执行目标方法后,模拟关闭事务") ;
return object ;
}
//异常通知
@AfterThrowing(value = "myPointCut()" , throwing = "e")
public void except(Throwable e){
System.out.println("异常通知:" + "程序执行异常" + e.getMessage()) ;
}
//后置(最终)通知
@After("myPointCut()")
public void After(){
System.out.println("最终通知:模拟释放资源") ;
}
}
2-注解目标类,使用 注解@Repository将目标类dynamic.jdk.TestDaoImpl注解为目标对象,注解代码如下
@Repository("testDao")
3-创建配置文件,在src目录下创建配置文件applicationContext.xml,并在配置文件中指定需要扫描的包,使注解生效,同时需要启动注解的AspectJ支持
<?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:context="http://www.springframework.org/schema/context"
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/context
https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--指定需要扫描的包-->
<context:component-scan base-package = "aspectj.annotation"/>
<context:component-scan base-package = "dynamic.jdk"/>
<!--启动基于注解的AspectJ支持-->
<aop:aspectj-autoproxy/>
</beans>
4-创建测试类,在aspectj.annotaion包中创建测试类AnnotationAspectJTest,并在该类中加载增强后的目标对象,执行 相应方法。
import dynamic.jdk.TestDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationAspectJTest {
public static void main(String[] args){
//初始化Spring容器,加载配置文件
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml") ;
//获取增强后的目标对象
TestDao testDaoAdvice = (TestDao) appCon.getBean("testDao");
testDaoAdvice.save() ;
System.out.println("=================") ;
testDaoAdvice.modify() ;
System.out.println("=================") ;
testDaoAdvice.delete() ;
}
}
5-测试结果如下:
6-若在dynamic.jdk包的TestImpl类的save方法总添加异常代码,例如:int n = 100 / 0 ;
然后重新运行测试类,测试结果如下:
以上是关于两种方式开发AspectJ的主要内容,如果未能解决你的问题,请参考以下文章