package com.itheima.aspect; public class MyAspect { public void check_Permissions(){ System.out.println("模拟检查权限..."); } public void log() { // TODO Auto-generated method stub System.out.println("记录日志"); } }
package com.itheima.aspect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.itheima.jdk.UserDao; public class JdkProxy implements InvocationHandler{ private UserDao userDao; public Object createProxy(UserDao userDao){ this.userDao=userDao; ClassLoader classLoader=JdkProxy.class.getClassLoader(); Class[]clazz = userDao.getClass().getInterfaces(); return Proxy.newProxyInstance(classLoader, clazz, this); } @Override public Object invoke(Object proxy,Method method,Object[]args) throws Throwable{ MyAspect myAspect = new MyAspect(); myAspect.check_Permissions(); Object obj = method.invoke(userDao,args); myAspect.log(); return obj; } }
package com.itheima.aspect; import com.itheima.jdk.UserDao; import com.itheima.jdk.UserDaoImpl; public class JdkTest { public static void main(String[] args) { JdkProxy jdkProxy= new JdkProxy(); UserDao userDao = new UserDaoImpl(); UserDao userDao1= (UserDao)jdkProxy.createProxy(userDao); userDao1.addUser(); userDao1.deleteUser(); } }
AOP动态代理方法的实现如上,不过总体来说还是比较麻烦,要修改的地方也太多。
后来有人开发了aspectJ工具,通过aspectJ,可以方便的使用切面,把代理类和实现类与代理类之间的耦合解除。
aspectJ有两种实现方式,一种是xml,一种是注解。
这里要注意需要导入aspectJ的相关包
方式1:通过xml实现
将代理类和实现类与代理类之间的调用关系,全部写进xml中:
即以上的代码修改一下:
切面:
package com.itheima.aspectj.xml; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class MyAspect { public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知"); System.out.println("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法位:"+joinPoint.getSignature()); } public void myAfterReturning(JoinPoint joinPoint){ System.out.println("后置通知"); System.out.println(",被植入增强处理的目标方法位:"+joinPoint.getSignature()); } public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("环绕开始:执行方法之前,模拟开启事务"); Object object=joinPoint.proceed(); System.out.println("环绕结束:执行方法之后,模拟关闭事务"); return object; } public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("异常通知:"+"出错了"+e.getMessage()); System.out.println("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法位:"+joinPoint.getSignature()); } public void myAfter(JoinPoint joinPoint){ System.out.println("最终通知:模拟方法结束后释放资源"); } }
xml配置:
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <bean id = "userDao" class = "com.itheima.jdk.UserDaoImpl"/> <bean id = "myAspect" class = "com.itheima.aspectj.xml.MyAspect"/> <aop:config> <aop:aspect id = "aspect" ref = "myAspect"> <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"/> <aop:around method="myAround" pointcut-ref="myPointCut"/> <aop:after-throwing method = "myAfterThrowing" pointcut-ref = "myPointCut" throwing="e"/> <aop:after method="myAfter" pointcut-ref="myPointCut"/> </aop:aspect> </aop:config> </beans>
测试类:
package com.itheima.aspectj.xml; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.itheima.jdk.UserDao; public class AspectjXmlTest { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/itheima/aspectj/xml/applicationContext.xml"); UserDao userDao= (UserDao) applicationContext.getBean("userDao"); userDao.addUser(); userDao.deleteUser(); } }
执行结果:
前置通知 目标类是:com.itheima.jdk.UserDaoImpl@59309333 ,被植入增强处理的目标方法位:void com.itheima.jdk.UserDao.addUser() 环绕开始:执行方法之前,模拟开启事务 添加用户 最终通知:模拟方法结束后释放资源 环绕结束:执行方法之后,模拟关闭事务 后置通知 ,被植入增强处理的目标方法位:void com.itheima.jdk.UserDao.addUser() 前置通知 目标类是:com.itheima.jdk.UserDaoImpl@59309333 ,被植入增强处理的目标方法位:void com.itheima.jdk.UserDao.deleteUser() 环绕开始:执行方法之前,模拟开启事务 删除用户 最终通知:模拟方法结束后释放资源 环绕结束:执行方法之后,模拟关闭事务 后置通知 ,被植入增强处理的目标方法位:void com.itheima.jdk.UserDao.deleteUser()
aspectJ减少了动态代理实现中出现的代码臃肿,但是,需要修改spring的配置文件,不是很好。
于是衍生了注解方式实现AOP,完美解决了修改spring配置文件的问题。
package com.itheima.aspectj.annotation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class MyAspect { //defined the pointcut @Pointcut("execution(* com.itheima.jdk.*.*(..))") private void myPointCut(){} //pre-notification @Before("myPointCut()") public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知"); System.out.println("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法位:"+joinPoint.getSignature()); } //after-notification @AfterReturning(value="myPointCut()") public void myAfterReturning(JoinPoint joinPoint){ System.out.println("后置通知"); System.out.println(",被植入增强处理的目标方法位:"+joinPoint.getSignature()); } //around-notification @Around("myPointCut()") public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("环绕开始:执行方法之前,模拟开启事务"); Object object=joinPoint.proceed(); System.out.println("环绕结束:执行方法之后,模拟关闭事务"); return object; } @AfterThrowing(value="myPointCut()",throwing="e") public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("异常通知:"+"出错了"+e.getMessage()); System.out.println("目标类是:"+joinPoint.getTarget()); System.out.println(",被植入增强处理的目标方法位:"+joinPoint.getSignature()); } @After("myPointCut()") public void myAfter(JoinPoint joinPoint){ System.out.println("最终通知:模拟方法结束后释放资源"); } }
<context:component-scan base-package="com.itheima" /> <aop:aspectj-autoproxy />
public class AspectjXmlTest { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/itheima/aspectj/annotation/applicationContext.xml"); UserDao userDao= (UserDao) applicationContext.getBean("userDao"); userDao.addUser(); userDao.deleteUser(); } }