基于XML的声明式AspectJ
基于xml的AspectJ:一个AOP框架:通过xml文件配置:通过aop:config元素定义切面点,通知等。
常用元素与子元素嵌套关系:
aop:config的子元素:aop:aspect
aop:aspect的子元素:(id:唯一标识,ref:引用普通的spring bean)
1.aop:pointcut(配置全局切入点):(id:唯一标识,expression:写切入点表达式)
2.aop:before(配置前置通知)(method:想要增强的方法,pointcut-ref:把配置的切入点的id写进来)
3.aop:after-returning(配置后置通知)(method:同上,pointcut-ref:同上,returning:通过该形参访问目标方法返回值)
4.aop:around(配置环绕通知)(method:同上,pointcut-ref:同上)
5.aop:after-throwing(配置异常通知)(method:同上,pointcut-ref:同上,throwing:通过该形参访问方法返回值)
6.aop:after(配置最终通知)(method:同上,pointcut-ref:同上)
结构:
aop:config
aop:aspect(配置切面)
<aop:pointcut />(配置全局切入点)
<aop:befor />
<aop:after-returning />
<aop:around />
<aop:after-throwing />
<aop:after />
</aop:aspect>
</aop:config>
例如:
切入点:通俗易懂的说,你想在哪个方法的前或者后增加通知/增强处理。那个位置(那个方法)就是切入点,你在那个切入点前添加了通知,就是前置通知。你在那个切入点后添加通知,就是后置通知。
切入点表达式:execution表达式:
访问修饰符 返回值类型 类路径 目标方法 参数 异常类型(加粗为必须值)
例如:public void com.meicong.jdk.UserDaoImpl.adduser()(…)
访问修饰符的位置填写一个 *,代表随意,任意都可以。
//定义切面类
public class MyAspect {
//前置通知:
public void myBefore(JoinPoint joinPoint) {
//用JoinPoint接口作为参数获取目标对象的信息,方法,类名等。(记住这么写,获取信息用)
System.out.print(" 前置通知:模拟执行权限检查. . . , " ) ;
System.out.print(" 目标类是: "+joinPoint.getTarget() ); //joinPoint.getTarget:目标类,也就是要增加通知的那个目标类。Target:目标。
System.out.println(" ,被织入增强处理的目标方法为: " +joinPoint.getSignature().getName()) ; //获取目标方法。
}
//后置通知:
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print(" 后置通知:模拟记录日志. . . ," );
System.out.println(" 被植入增强处理的目标方法为: " + joinPoint.getSignature() .getName());
}
//环绕通知:前和后都有,返回值为Object,参数这里有改变,这是JoinPoint的子接口,必须有异常处理。
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
System.out.println("环绕开始:执行目标方法之前,模拟开启事务. . . ") ;
Object obj = proceedingJoinPoint.proceed() ; //执行当前目标方法,也就是你准备要添加通知的那个方法,他的前后都加了通知。
System out println("环绕结束 执行门标方法之后 模拟关闭事务 . . ") ;
return obj; //返回obj
}
//异常通知:出现异常时的通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e ) {
System out println("异常通知:"+"出错了" + e.getMessage());
}
//最终通知:最后一定会执行的通知
public void myAfter() {
System out println("最终通知 模拟方法结束后的释放资源 . . ") ;
}
}
//xml配置文件主要代码:
<bean id="userDao" class=" com.itheima.jdk.UserDaolmpl" /> //配置目标类
<bean id="myAspect" class="com.itheima.aspectj.xml.MyAspect" /> //配置切面类
<aop:config>
<aop:aspect ref="myAspect " > //配置切面,ref指向的就是切面类的id
<aop:pointcut expression="execution(* com.itheima.jdk.*.*(..))" //配置切入点,就是要增强什么方法,用切入点表达式
id="myPointCut" />
<aop:before method="myBefore" pointcut-ref="myPointCut" /> //前置,对用的那个前置方法,把这个前置方法加入到目标对象上。
<aop:after-returning method="myAfterReturning" //指向切入点。
pointcut-ref="myPointCut" returning="returnVal" /> //同理 后置通知可返回方法返回值,returning。
<aop:around method="myAround" pointcut-ref="myPointCut" />
<aop:after-throwing method="myAfterThrowing"
pointcut-ref="PointCut" throwing="e" /> //异常处理
<aop:after method="myAfter" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>
public class TestXmlAspectj {
public static void main(String args[)) {
String xmlPath =
"com/itheima/aspectj/xml/applicationContext . xml";
ApplicationContext applicationContext =
new ClassPath nlApplicationContext(xmlPath);
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.addUser();
}
}