本文共 6797 字,大约阅读时间需要 22 分钟。
Spring AOP建立在代理之上,所以先对代理有个简单的认识也是很有必要的,下面结合代码来进行简要说明。
public class Student { public String name ; public int age ;}public interface IStudentService { /** * 添加学生 * */ void addStudent(Student student) ; /** * 删除学生 * */ void removeStudent(String studentId) ; }public class DefaultStudentService implements IStudentService { @Override public void addStudent(Student student) { System.out.println("新增学生信息"); } @Override public void removeStudent(String studentId) { System.out.println("删除ID为" + studentId+"的学生信息"); }}
Java的动态代理主要涉及到下面两个类型
1)java.lang.reflect.InvocationHandler接口/**代理实例的调用处理程序实现的接口;每个代理实例都有一个关联的调用处理程序。在代理实例上调用方法时,方法调用将被处理并发送到其调用处理程序的invoke方法。*/public interface InvocationHandler { /** @param proxy 动态生成的代理对象实例 @param method 被代理对象调用的方法 @param args 被调用的方法的参数 @return 从代理实例上的方法调用返回的值,其类型必须和被代理接口中所定义的返回类型兼容。 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}
2)java.lang.reflect.Proxy对象
简单的说,Java动态代理就是通过Java的Proxy对象来创建某个实例对象的代理对象,在调用代理对象的时候便会触发调用InvocationHandler的invoke方法,我们在invoke方法中可以添加一些额外的代码来扩充能力,同时在invoke中我们可以判断哪个方法被调用,然后通过反射执行被代理对象上的这个方法。
/** * Java的动态代理技术【代理整个接口类】 */ public static void javaDyncProxy() { // 要被代理的目标对象 DefaultStudentService studentService = new DefaultStudentService(); // 代理的调用处理器【当我们通过动态代理对象调用任何一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用】 StudentServiceInvocationHandler invocationHandler = new StudentServiceInvocationHandler(studentService); // 创建代理对象 IStudentService service = (IStudentService)Proxy.newProxyInstance(studentService.getClass().getClassLoader(), studentService.getClass().getInterfaces(), invocationHandler); service.addStudent(new Student()); } public static class StudentServiceInvocationHandler implements InvocationHandler { private IStudentService target; public StudentServiceInvocationHandler(IStudentService studentService) { this.target = studentService; } /* * @param proxy * 真实对象的真实代理对象;InvocationHandler本身,例如这里的:StudentServiceInvocationHandler */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("是的,你已经是在使用Proxy了"); return method.invoke(target, args); } } public static void main(String[] args) { javaDyncProxy() ; }
执行main方法后,得到的打印输入如下
是的,你已经是在使用Proxy了新增学生信息
前面的文章中有介绍过Spring AOP中的一些概念,其中包括Advice和Pointcut。 Pointcut用于筛选类和方法,而Advice负责确实执行点,通过两则的结合就有了Advisor(切面)。
我们先看下SpringAOP中这些对象的关系。
由上图可知
1)Pointcut接口依赖于ClassFilter和MethodMatcher两个接口,通过这两个接口来达到筛选类和方法的目的2)Advice接口【是个Tag Interface】包含了众多的子接口,通过子接口来扩展其功能,每个子接口都分别代表不同的方法执行点(内部的抽象方法便是添加增强代码的地方)3)Adisor接口依赖于Advice接口,代表一个类中的所有方法的某些执行点,其最常用的子接口类型PointcutAdvisor有添加了对Pointcut接口的依赖,表示某些类中某些方法的某些执行点下面我们更进一步的看看各个接口都有哪些实现
ThrowsAdvice是一个Tag interface,实现类具有以下任意一个或多个方法实现均可:
public void afterThrowing(Exception ex)public void afterThrowing(RemoteException)public void afterThrowing(Method method, Object[] args, Object target, Exception ex)public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)上面通过类图展现了SpringAOP中几个关键概念间的关系,下面再看看SpringProxy的类图
1)ProxyCreatorSupport与AopProxyFactory关联,在内部默认创建DefaultAopProxyFactory对象
2)AopProxyFactory依赖AopProxy接口,AopProxy的实现类包含了基于Java动态代理的JdkDynamicAopProxy和基于cglib的CglibAopProxy对象
3)我们在使用AopProxy的时候,内部会根据我们的设置来动态的选择使用Java动态代理还是基于cglib的代理。
下面通过示例代码来说明Spring Aop的以上这些对象
/** * 定义“方位”以及对应的增强代码。 * 使用时,如果没提供具体的Ponitcut,该增强会织入到目标类的所有方法上。 * */public class StudentServiceAdvice implements MethodBeforeAdvice, AfterReturningAdvice,ThrowsAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("调用方法" + method.getName() +"前"); } @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("调用方法" + method.getName() +"返回后"); } /** * 方法名必须是afterThrowing,前三个参数是可选【同时都出现或都不出现】,最后个参数不行是Throwable或子类。 * 可以定义多个afterThrowing方法,Spring会自动选用最匹配的增强方法。 * */ public void afterThrowing(Method method, Object[] args, Object target,RuntimeException e) { System.out.println("调用方法" + method.getName() +"抛出异常后"); }}
/** * 只用增强应用到类上的所有方法上 */ public static void springProxy() { // 要被代理的目标对象 DefaultStudentService studentService = new DefaultStudentService(); /* * 代理工厂根据代理配置在内部使用AopProxy类型的代理创建代理对象,AopProxy的实现类有以下两个: * 1)JdkDynamicAopProxy :基于Java的动态代理技术 * 2)Cglib2AopProxy : 基于CGLib的动态代理技术 * 在使用ProxyFactory的时候,如果通过setInterface()方法指定目标接口进行代理,则使用JdkDynamicAopProxy; * 如果针对类的代理或者设置SetOptimize(true),则使用Cglib2AopProxy; */ ProxyFactory factory = new ProxyFactory(); // 设置要被代理的接口类型 factory.setInterfaces(studentService.getClass().getInterfaces()); // 设置代理的目标对象 factory.setTarget(studentService); // 为代理目标添加增强[Advice包含了横切代码和连接点信息,所以本身就是一个简单的切面] factory.addAdvice(new StudentServiceAdvice()); // 生成代理实例 IStudentService proxy = (IStudentService) factory.getProxy(); // 调用方法 proxy.addStudent(new Student("test", 22)); proxy.removeStudent("10001"); }
调用方法addStudent前新增学生信息调用方法addStudent返回后调用方法removeStudent前删除ID为10001的学生信息调用方法removeStudent返回后
org.aspectj aspectjweaver 1.9.4 org.aspectj aspectjrt 1.9.4
@Aspectpublic class CommAspect { /** * 前置增强 * 所有目标类中的所有addStudent方法 * */ @Before("execution (* addStudent(..))") public void defore(JoinPoint joinPoint) { System.out.println(">>>>befor addStudent"); }}public static void springAspectProxy() { // 要被代理的目标对象 DefaultStudentService studentService = new DefaultStudentService(); // 基于AspectJ的代理工厂 AspectJProxyFactory factory = new AspectJProxyFactory(); // 设置代理目标 factory.setTarget(studentService); // 添加切面类 factory.addAspect(CommAspect.class); // 生成代理实例 IStudentService proxy = (IStudentService) factory.getProxy(); // 调用方法 proxy.addStudent(new Student("test", 22)); proxy.removeStudent("10001"); }
执行后输出:
>>>>befor addStudent新增学生信息删除ID为10001的学生信息
转载于:https://blog.51cto.com/dengshuangfu/2400191