Spring AOP建立在代理之上,所以先对代理有个简单的认识也是很有必要的,下面结合代码来进行简要说明。
1,首先定义一个接口和实体对象
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+"的学生信息");
}
}
2,Java的动态代理技术
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中我们可以判断哪个方法被调用,然后通过反射执行被代理对象上的这个方法。
3,使用Java动态代理实例
/**
* 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了
新增学生信息
4,Spring AOP
前面的文章中有介绍过Spring AOP中的一些概念,其中包括Advice和Pointcut。 Pointcut用于筛选类和方法,而Advice负责确实执行点,通过两则的结合就有了Advisor(切面)。
我们先看下SpringAOP中这些对象的关系。
由上图可知
1)Pointcut接口依赖于ClassFilter和MethodMatcher两个接口,通过这两个接口来达到筛选类和方法的目的
2)Advice接口【是个Tag Interface】包含了众多的子接口,通过子接口来扩展其功能,每个子接口都分别代表不同的方法执行点(内部的抽象方法便是添加增强代码的地方)
3)Adisor接口依赖于Advice接口,代表一个类中的所有方法的某些执行点,其最常用的子接口类型PointcutAdvisor有添加了对Pointcut接口的依赖,表示某些类中某些方法的某些执行点
下面我们更进一步的看看各个接口都有哪些实现
Pointcut实现类关系图
Advice接口关系图
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)
Advisor关系图
上面通过类图展现了SpringAOP中几个关键概念间的关系,下面再看看SpringProxy的类图
1)ProxyCreatorSupport与AopProxyFactory关联,在内部默认创建DefaultAopProxyFactory对象
2)AopProxyFactory依赖AopProxy接口,AopProxy的实现类包含了基于Java动态代理的JdkDynamicAopProxy和基于cglib的CglibAopProxy对象
3)我们在使用AopProxy的时候,内部会根据我们的设置来动态的选择使用Java动态代理还是基于cglib的代理。
下面通过示例代码来说明Spring Aop的以上这些对象
使用ProxyFactory
/**
* 定义“方位”以及对应的增强代码。
* 使用时,如果没提供具体的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返回后
使用AspectJProxyFactory
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.4</version>
</dependency>
@Aspect
public 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的学生信息
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/191925.html