Spring AOP基础:代理模式
来源:互联网 发布:安卓手机java模拟器 编辑:程序博客网 时间:2024/06/15 01:02
代理模式
代理模式:在对已有方法进行改进时,不直接修改原有方法或代码,而是提供第三方。该第三方含有代理角色的引用,并根据需求增加相应的功能。
代理模式在程序设计中有非常重要的应用,AOP就是针对代理的一种应用。在生活中代理也无处不在,比如翻墙,比如开代理打韩服等等。
学习代理模式,先从简单的代码开始。
先定义一个简单的接口
public interface Hello{ void sayHello();}
再实现一个基本的Hello实现
public class HelloImpl implements Hello{ @override public void sayHello{ System.out.println("Hello"); }}
如果要在println方法前分别需要一些处理逻辑,该怎么么做呢?如果是以前的我,我会直接将处理逻辑写死在在HelloImpl的sayHello方法中。但是这样的写法在大多数情况下是不妥的,就好像没学面向对象以前,将所有的方法逻辑写在一个类里面。这样的写法,会使得一个方法越来越长,处理逻辑的实现也会将类变得越来越庞大,而且这样处理逻辑可能与该类的其他方法无关。所以最好的方法是将这些处理逻辑交于代理处理。
对于我们的HelloImpl类,我们写一个HelloProxy类,让该类调用HelloImpl的sayHello方法,并在调用的前后进行相应的逻辑处理。
public class HelloProxy implements Hello{ Hello helloImpl; HelloProxy(){ helloImpl=new HelloImpl(); } @Override public void sayHello(){ before(); helloImpl.sayHello(); after(); } private void before(){ System.out.println("before"); } public void after(){ System.out.println("after"); }}
在这段代码中,我们用HelloProxy实现Hello接口(和HelloImpl实现相同的接口),并且在构造方法中new出HelloImpl实例,则我们可以在HelloProxy的sayHello()方法中调用HelloImpl的sayHello()方法。这样的话,我们就可以在调用前后添加相应的before和after方法,并在这两个方法中去实现相应的前后处理逻辑。
我们再用main方法测试一下
public static void main(String args[]){ HelloProxy helloProxy=new HelloProxy(); helloProxy.sayHello(); }
结果如下
beforehelloafter
这个HelloProxy就是简单的代理。这样的代理称为静态代理。所谓静态,就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
这样的静态代理几个缺点:
1. 如果要代理的方法很多,那么静态代理类的规模也势必很大。
2. 如果接口增加一个方法,那么所有代理类也必须实现此方法,如此就增加了代码维护的复杂度
为了解决静态代理的问题,我们使用JDK提供的动态代理方案DynamicProxy:
public class DynamicProxy implements InvocationHandler{ private Object object; public DynamicProxy(Object object) { this.object=object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub before(); Object result=method.invoke(object, args); after(); return result; } private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); }}
DynamicProxy实现了InvocationHandler接口,那么必须实现invoke方法,在invoke方法中,直接通过反射去调用被包装类的方法,在调用前后实现 分别处理before和after,最后将result返回。
在main中测试:
public static void main(String args[]){ Hello hello=new HelloImpl(); DynamicProxy dynamicProxy=new DynamicProxy(hello); Hello helloProxy=(Hello) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), dynamicProxy); helloProxy.sayHello(); }
结果如下:
beforehelloafter
在上述代码中,我们用这个通用的DynamicProxy类去包装HelloImpl实例,然后调用JDK给我们提供的Proxy类工厂方法newProxyInstance去动态的创建一个Hello接口的代理类,最后调用这个代理类的sayHello方法。结果和静态代理结果一样。
其实,动态代理就是动态生成XxxProxy。和静态代理相比,动态代理类的源码是在程序运行期间由JVM根据反射等机制动态生成的。
代理类和委托类的关系是在程序运行时确定的,所有如果需要在不同类的不同方法增加相同的处理逻辑,我们只需要一个动态代理类就可以实现,这就是动态代理的优点。
在main方法中我们可以看到,Proxy.newProxyInstance方法要有三个参数:
1. ClassLoader;
2. 该实现类的所有接口
3. 动态代理对象
在调用结束后还需要类型的强制转换。如果我们的动态代理需要代理多个对象,那么上述代码需要重复多次。
为了避免Proxy.newInstance方法出现多次(减少代码量和简化动态代理类的使用),我们将动态代理对象实例化部分代码封装起来(使用泛型):
@SuppressWarnings("unchecked") public <T> T getProxy(){ return (T)Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this); }
如此一来,我们的DynamicProxy的使用将更加方便,代码也看起来简洁清晰多了:
public static void main(String args[]){ DynamicProxy dynamicProxy=new DynamicProxy(new HelloImpl()); Hello helloProxy=dynamicProxy.getProxy(); helloProxy.sayHello(); }
除了减少代理类这个优点,相对于静态代理,动态代理在接口变化的时候,代理类不需要变化,而静态代理类则需要相对应的改动。
但是,我们发现,上述JDK动态代理只能代理有接口的类,如果需要代理的类没有接口,那么JDK动态代理就无用武之地。
为了解决代理没有接口的类的问题,我们使用开源的CGLIB类库。
public class CGLIBProxy implements MethodInterceptor{ private static CGLIBProxy instance=new CGLIBProxy(); private CGLIBProxy() { } public static CGLIBProxy getInstance(){ return instance; } @SuppressWarnings("unchecked") public <T> T getProxy(Class<T>cls){ return (T)Enhancer.create(cls, this); } @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { before(); Object result=proxy.invokeSuper(target, args); after(); return result; } private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); }}
从上述代码可以看出,CGLIB类库的使用和JDK动态代理类似。但是CGLIB类库可以代理没有接口的类,且速度相较于JDK DynamicProxy更快。
测试使用及运行结果如下:
public class Greet { public void say(String str){ System.out.println("hello"+str); } public static void main(String args[]){ Greet greetProxy=CGLIBProxy.getInstance().getProxy(Greet.class); greetProxy.say("shan"); }}运行结果:beforehelloshanafter
至此,代理模式基本内容也就介绍完毕。AOP是基于JDK DynamicProxy和CGLIB代理,但是又不仅限于这些。要学好spring,AOP是重中之重。而代理又是AOP的基石,所以对代理理解并学以致用才是王道。
- Spring AOP基础:代理模式
- Spring AOP代理模式
- Spring AOP 代理模式
- Spring AOP之代理模式
- Spring aop之代理模式
- Spring AOP中的代理模式
- 代理模式及spring AOP
- Spring-AOP的代理模式
- Spring AOP基础—JDK动态代理
- Spring AOP基础-CGLib动态代理
- spring AOP的基础:动态代理
- Spring学习历程 --- AOP基础之代理
- Spring AOP 之 java 动态代理基础
- Spring AOP---切面编程基础(动态代理)
- Spring学习总结2(AOP-代理模式)
- 代理模式(proxy)和spring AOP
- Spring中AOP的代理模式
- spring aop 实现原理---代理模式
- Android Studio你不知道的调试技巧
- java中为什么需要public static void main(String[] args)这个方法
- ReactNative学习过程
- Java中按值传递和按引用传递的区别
- 数据迁移测试
- Spring AOP基础:代理模式
- java多态性理解
- 清理和删除svn信息
- 某证券公司高级系统架构师内训圆满结束!
- error和exception有什么区别?
- IOS开发四种常见存储 归档解归档(Archive)/偏好设置(NSUserDefaults)/沙盒存储 /SQLite3.0
- LeetCode Top K Frequent Elements
- 学习react-native不错的帖子或者资源
- 同步和异步有何异同,在什么情况下分别使用他们?举例说明。