一、AOP概述
AOP思想的实现一般都是基于代理模式,JDK动态代理模式只能代理接口,而不能代理类。但是SpringAOP同时支持CGLIB、JDK、ASPECTJ这三种代理模式,因此,如果目标的对象实现了接口,SpringAOP将会采用JDK动态代理,如果目标对象没有实现接口,SpringAOP切换成CGLIB动态代理。
在实际情况下,我们通常需要对一个接口实现多个切面,比如日志打印、分布式锁、权限校验等等。这时候我们就会面临一个优先级的问题,这么多的切面如何告知Spring执行顺序呢?这就需要我们定义每个切面的优先级,我们可以使用注解@Order(i)来表示切面的优先级,i的值越小,优先级越高。假设我们现在一共有两个切面,一个日志处理切面,设置其@Order(100);一个分布式锁,设置其@Order(99),那么分布式锁的优先级是高于日志处理的,对于通知@Before来说,先执行分布式锁,再执行日志处理;对于通知@After和@AfterReturning来说,先执行日志处理,再执行分布式锁,这样就可以完成一个首尾的对应,也可以理解为先进后出原则。
二、静态代理
接口类:
interface Person { void speak();}
实体类:
class Actor implements Person {
private String content;
public Actor(String content) { this.content = content;}
public void speak(){
System.out.println(this.content);
}
}
代理类:
class Agent implements Person {
private Actor actor;
private String before;
private String after;
public Agent(Actor actor, String before, String after){
this.actor = actor;
this.before = before;
this.after = after;
}
public void speak(){
System.out.println("前置通知:" + this.before);
this.actor.speak();
System.out.println("后置通知:" + this.after);
}
}
测试类:
public class StaticProxyTest{
public static void main(String[] args){
Actor actor = new Actor("实体类的真正内容");
Agent agent = new Agent(actor, "前置内容", "后置内容");
agent.speak();
}
}
二、动态代理
1、JDK自带动态代理
public interface InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
proxy:被代理的类的实例
method:调用被代理的类的方法
args:该方法需要的参数
我们实现该接口,在invoke方法中调用实体类的方法,并在其前后进行动态操作,从而实现动态代理。另外一个很重要的静态方法是java.lang.reflect包中的Proxy类的newProxyInstance方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException;
loader:被代理类的类加载器
interfaces:被代理类的接口数组
h:调用处理器类的对象实例
该方法会返回一个被修改过的类的实例,从而可以自由的调用该实例的方法。
Person接口:
public interface Person{
public void show();
}
Actor实体类:
public class Actor implements Person{
public void show(){
System.out.println("真正实现的方法");
}
}
Agent代理类:
public class DynamicAgent{
static class Agent implements InvocationHandler{
private Object proxy;
public Agent(Object proxy){
this.proxy = proxy;
}
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
System.out.println("自己添加的前置通知");
//真正调用的方法
Object res = method.invoke(this.proxy, args);
System.out.println("自己添加的后置通知");
return res;
}
public static Object agent(Class interfaceClazz, Object proxy){
return Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz}, new Agent(proxy));
}
}
}
测试类ReflectTest:
public class ReflectTest{
public static void main(String[] args) throws InvocationTargetException, IllegralAccessException {
Person person = (Person)DynamicAgent.agent(Person.class, new Actor());
person.show();
}
}
这样以后对于不同的实现类来说,可以用同一个动态代理类来进行代理,但是这种方法有个缺点,就是被代理的类一定要是实现了某个接口的。
2、CGLIB动态代理
同样的CGLIB也有两个重要的方法,在MethodInterceptor接口中的getInstance(Object proxy)和intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)方法 。
public class CglibAgent implements MethodInterceptor {
private Object proxy;
public Object getInstance(Object proxy){
this.proxy = proxy;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.proxy.getClass);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] object, MethodProxy methodProxy) throws Throwable{
System.out.println("自己添加的前置通知");
Object res = methodProxy.invokeSuper(this.proxy, args);
System.out.println("自己添加的后置通知");
return res;
}
//测试
public static void main(String[] args){
CglibAgent cglibAgent = new CglibAgent();
Actor actor = (Actor)cglibAgent.getInstance(new Actor());
actor.show();
}
}
使用CGLIB处理之后,可以直接对实体类进行动态代理。