我不想讲很规范的定义,因为那只会增加我们对AOP学习的压力,一开始就来一堆名字定义,我是不是要去记这些概念才能理解AOP呢,其实不是,我想这些概念只不过是原理之后的规范而已,大家得统一一个规范,不然你说你的APO,我说我的AOP,不好理解,但是原理是通的,所以我会先用简单的问题一步步展现原理,没有什么名次概念,只有简单的,接口,方法,最多就是个动态代理。我们暂且把AOP就当做给我的方法增加点什么操作吧。
简单的例子,我们定义了一个接口,有一个实现类,一个测试类:
public interface MyServiceInterface {
void doService();
}
public class MyServiceimp implements MyServiceInterface {
public void doService() {
System.out.println("========doService========");
}
}
public class Test {
public static void main(String[] args) {
MyServiceInterface myService=new MyServiceimp();
myService.doService();
}
}
输出:
这个最简单不过了吧,但是我们现在有新需求了,我想在执行的doService
方法前后增加log日志显示,但是不能修改我的源码。本来想直接改源码不就得了,但是现在没办法,源码不让动,所以这个时候就会想那我重新弄个类,然后把他放进来,在他前后增加方法不就可以了,于是有了第二版的。
为了简单起见,我创建了一个新的类:
package proxy;
import aop.MyServiceInterface;
public class AopProxy1 implements MyServiceInterface {
MyServiceInterface myServiceInterface;
public void setMyServiceInterface(MyServiceInterface myServiceInterface) {
this.myServiceInterface = myServiceInterface;
}
public void doService() {
System.out.println("======doService之前=======");
myServiceInterface.doService();
System.out.println("======doService之后=======");
}
}
然后测试:
package proxy;
import aop.MyServiceInterface;
import aop.MyServiceimp;
public class Test {
public static void main(String[] args) {
MyServiceInterface myServiceimp=new MyServiceimp();
AopProxy1 aopProxy1=new AopProxy1();
aopProxy1.setMyServiceInterface(myServiceimp);
aopProxy1.doService();
}
}
结果:
貌似实现了我们要的东西。是的确实,而且我们用了一种代理的思想,对外服务的对象已经是代理对象了,代理对象对我们的真实对象的方法进行了扩展。但是问题又来了,如果我们有很多类,很多方法,每个方法都要扩展,那岂不是一个类要一个代理对象啦,有100个类,我还要重新写100个,而且基本都是重复性的劳动,有没有更好的实现方法呢?当然有,叫做动态代理,其实动态代理一般有两种,一种是JDK的,一种叫CGLIB,具体的区别可以百度下,简单说系就是JDK的是需要接口,用的是反射,而CGLIB可以是普通类,对字节码操作。
其实就是对我上面的这种做法做了增强,不需要每次都创建一个代理类,只需要创建通用动态代理类,把想代理的对象传进去,实现了InvocationHandler
接口,原理是利用反射调用方法,具体可以看内部的源码,我这里只是做简单的使用:
package Proxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKDynamicProxy implements InvocationHandler {
Object target;
public Object getProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("======JDKDynamicProxy 调用之前=======");
method.invoke(this.target, args);
System.out.println("======JDKDynamicProxy 调用之后=======");
return null;
}
}
package Proxy2;
import aop.MyServiceInterface;
import aop.MyServiceimp;
public class Test {
public static void main(String[] args) {
MyServiceInterface serviceInterface=new MyServiceimp();
JDKDynamicProxy jdkDynamicProxy=new JDKDynamicProxy();
MyServiceInterface proxy = (MyServiceInterface)jdkDynamicProxy.getProxy(serviceInterface);
proxy.doService();
}
}
结果也是对的,当然只是很简单的例子,但是我发现不管我换什么类,调用前和调用后的log信息是一样的System.out.println("======JDKDynamicProxy 调用之前=======");
这句话被写死在了里面,如果我想要不同的类做不同的事,那要怎么办呢,我当然希望这块可以提取出来,放在另一个接口里,只要在接口里定义两个方法,然后让实现类去实现,最后把实现类传到动态代理类里,好,那我们试试。
我们定义一个接口,叫做拦截器,简单就是说在我的方法前后拦截,就可以做扩展啦:
package Proxy3;
public interface Interceptor {
void before();
void after();
}
一个log的实现类
package Proxy3;
public class LogInterceptor implements Interceptor {
public void before() {
System.out.println("我只是在方法前打log");
}
public void after() {
System.out.println("我只是在方法后打log");
}
}
一个是时间的实现类:
package Proxy3;
public class TimeInterceptor implements Interceptor {
public void before() {
System.out.println("我是在方法前记录时间:");
}
public void after() {
System.out.println("我是在方法后记录时间");
}
}
动态代理增强类:
package Proxy3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKDynamicProxyAdvanced implements InvocationHandler {
Object target;
Interceptor interceptor;
public void setInterceptor(Interceptor interceptor) {
this.interceptor = interceptor;
}
public Object getProxy(Object target, Interceptor interceptor) {
this.interceptor=interceptor;
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
interceptor.before();
method.invoke(this.target, args);
interceptor.after();
return null;
}
}
测试类:
package Proxy3;
import aop.MyServiceInterface;
import aop.MyServiceimp;
public class Test {
public static void main(String[] args) {
MyServiceInterface serviceInterface = new MyServiceimp();
JDKDynamicProxyAdvanced jDKDynamicProxyAdvanced = new JDKDynamicProxyAdvanced();
MyServiceInterface proxy = (MyServiceInterface) jDKDynamicProxyAdvanced.getProxy(serviceInterface, new TimeInterceptor());
proxy.doService();
jDKDynamicProxyAdvanced.setInterceptor(new LogInterceptor());
proxy.doService();
}
}
package cglib;
import aop.MyServiceimp;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibProxyAdvanced {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyServiceimp.class);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib 代理");
methodProxy.invokeSuper(o,objects);
return o;
}
});
MyServiceimp service = (MyServiceimp) enhancer.create();
service.doService();
}
}
结果:
貌似好像GCLib写起来简单点,也没有对扩展类有接口要求,不过这只是最简单的应用,具体其他的高级功能还要自己去研究GCLib啦。其实基本上AOP的简单原理就这些了,当然spring的AOP没那么简单啦,具体我后面会分析源码,本篇只是想介绍最基本的AOP,在不修修改源代码,没有侵入性的情况下对原方法进行扩展和增强。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵,部分图片来自网络,侵删。