AOP是指面向切面编程。
在学习AOP之前先来了解一下代理,因为传说中的AOP其实也对代理的一种应用。
首先来看这样一段代码:
public interface Hello { void say(String name); }
实现类:
public class HelloImpl implements Hello { public void say(String name) { System.out.println("Hello!"+name); } }
如果现在需要在say调用的前后做一些操作,那最简单的方法就是直接在say方面中增加代码,但这样肯定不够优雅。
这时候可以用第一种代理模式:静态代理
public class HelloProxy implements Hello { private Hello hello; public HelloProxy(){ hello=new HelloImpl(); } public void say(String name) { before(); hello.say(name); after(); } private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
这样我们在保留原来HelloImple中say方法的同时,用HelloProxy代理在say方法的前后增加了before和after
调用一下试试:
public static void main(String[] args){ Hello helloProxy=new HelloProxy(); helloProxy.say("Gary"); }
运行结果:
那么新的问题来了,如果每次都需要写一个代理类不也很麻烦吗,项目中就会有很多个xxxProxy,因此就出现了 JDK动态代理。
代码如下:
public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target){ this.target=target; } public <T> T getProxy(){ return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result=method.invoke(target,args); after(); return result; } private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
注:Proxy.newProxyInstance()参数有三个:
- ClassLoader
- 该实现类的所有接口
- 动态代理对象
在该类中target就是被代理的对象,该类实现了InvocationHandler接口,通过反射去动态创建Hello接口的代理类
那么现在的调用就变简单了:
public static void main(String[] args){ DynamicProxy dynamicProxy=new DynamicProxy(new HelloImpl()); Hello helloProxy= dynamicProxy.getProxy(); helloProxy.say("gary"); }
用了JDK动态代理后,我们觉得还是有问题,如果要代理一个没有接口的类,该怎么办呢,于是就轮到我们的 CGlib动态代理 出场了。
在Spring、Hibernate等框架中都用到了CGlib动态代理,maven资源如下:
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.6</version> </dependency>
他的使用需要实现MethodInterceptor类,并完成intercept方法。CGlib 提供的是方法级别的代理:
public class CGLibProxy implements MethodInterceptor { public <T> T getProxy(Class<T> cls){ return (T) Enhancer.create(cls,this); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object result=methodProxy.invokeSuper(o,objects); after(); return result; } private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
这样使用时就不需要提供接口了:
public static void main(String[] args){ CGLibProxy cgLibProxy= new CGLibProxy(); Hello hello=cgLibProxy.getProxy(HelloImpl.class); hello.say("Gary"); }
最后再改造一下,加上单例模式就更完美了
private static CGLibProxy instance=new CGLibProxy(); private CGLibProxy(){ }
public static CGLibProxy getInstance(){ return instance; }
调用就改为:
public static void main(String[] args){ Hello hello=CGLibProxy.getInstance().getProxy(HelloImpl.class); hello.say("Gary"); }