在上一篇文章-java代理详解讲解实现机制,一种是继承另外一种是组合,而且通过做实现也证明使用组合的方式更加的灵活。之后提到了代理的两种种类,一种是静态代理,另外一种是动态代理。上一篇文件中着重介绍的是静态代理(相对于动态代理很容易理解)。这一片文章就接着介绍动态代理。
动态代理实现的最终效果:通过以一个统一的方式实现对任意的接口/类的代理。相比较静态代理而言,我们可以不用再无限制的增加代理类,不用再写许多重复的代码。很符合面向对象设计原则中的"开闭原则":对修改关闭,对扩展开放。
动态代理有很多的实现,我们比较熟悉的就是JDK动态代理和CGLIB的动态代理,这种两技术也是spring实现AOP的使用的重要技术。
1. JDK动态代理
JDK底层封装了Proxy和InvocationHandler实现了对任意接口的代理。他们各自有自己的任务,Proxy主要负责动态生成代理类;InvocationHandler主要负责灵活指定代理内容。
1.1 动态生成代理类
想要实现“通过一个统一的方式方式对任意接口的代理”,使用的方式就是将接口以参数的形式传递到创建代理类的方法中。在JDK中负责创建代理类的类就是Proxy,他提供了两个方法创建代理,分别是newProxyInstance()和getProxyClass()。下面是JDK帮助文档中对他们的介绍:
Proxy | Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。 |
关于Proxy的相关介绍
从帮助文档中可以看出JDK给我们提供了两种创建代理类的方式,代码如下
- package cn.jdk.dynamicproxy;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import cn.jdk.dynamicproxy.Service;
-
- public class Main {
-
- public static void main(String[] args) throws Throwable {
-
- Object proxy = Proxy.newProxyInstance(
- ServiceImpl.class.getClassLoader(),
- ServiceImpl.class.getInterfaces(),
- new ServiceInvocationHandler(new ServiceImpl()));
- Service service1 = (Service)proxy;
- service1.add();
-
-
-
-
- Class<?> proxyClass = Proxy.getProxyClass(
- ServiceImpl.class.getClassLoader(),
- ServiceImpl.class.getInterfaces());
-
- Object serviceProxy = proxyClass.getConstructor(new Class[]{InvocationHandler.class})
- .newInstance(new ServiceInvocationHandler(new ServiceImpl()));
- Service service2 = (Service)serviceProxy;
- service2.add();
- }
- }
- package cn.jdk.dynamicproxy;
-
- public interface Service {
- public void add();
- }
- package cn.jdk.dynamicproxy;
-
-
-
-
-
-
-
-
- public class ServiceImpl implements Service{
- public void add() {
- System.out.println("向数据库中添加数据!");
- }
- }
这是创建代理类的代码,但不是完整的还加上下面的灵活指定代理内容。
2.2 灵活指定代理内容
代理内容:在上一篇文章我们曾经介绍过"代理模式",那个里面提到代理类是需要对委托类进行预处理,过滤消息,把消息转发给委托类,以及事后处理消息。而这些预消息,过滤消息,把消息转发给委托类,以及事后处理消息就是代理内容。
比如对于事务代理而言,在执行委托类的方法之前,开启事务就是代理内容;方法执行之后,关闭事务也是代理内容。
灵活指定:由用户决定代理内容是什么!
下面就将代码补全,看一下执行效果。
- package cn.jdk.dynamicproxy;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
-
- public class ServiceInvocationHandler implements InvocationHandler {
- private Object obj;
- public ServiceInvocationHandler(Service service) {
- super();
- this.obj = service;
- }
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result=null;
- System.out.println("jdk动态代理--开始事务");
- result = method.invoke(obj,args);
- System.out.println("jdk动态代理--结束事务 "+"\r\n");
- return result;
- }
- }
执行效果展示:
![](https://img-blog.csdn.net/20150605204419500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveV9sb3ZlX2Y=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
最后用一张UML图将上面的所有东西做一个总结。
![](https://img-blog.csdn.net/20150605204348745?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveV9sb3ZlX2Y=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2. CGLIB动态代理
上面的指能够动态生成接口的代理类,如果是一个类就不能够动态生成。而cglib能够动态生成类的代理类,这个类可以不用实现接口。
实现原理基本上是一样的,应用也是基本上一样的。
需要引用的jar包:cglib-nodep-2.2.2.jar 和 com.springsource.org.objectweb.asm-3.2.0.jar
直接上代码:
- package cn.cglib.dynamicproxy;
-
- import net.sf.cglib.proxy.Enhancer;
-
- public class Main {
-
- public static void main(String[] args) {
-
- Monkey monkey = (Monkey)Enhancer.create(
- Monkey.class,
- new MonkeyInvocationHandler());
- monkey.eat();
-
- monkey.type();
- }
- }
- package cn.cglib.dynamicproxy;
-
- public class Monkey {
-
- public void eat(){
- System.out.println("吃香蕉!");
- }
-
- public final String type(){
- return "金丝猴";
- }
- }
- package cn.cglib.dynamicproxy;
-
- import java.lang.reflect.Method;
-
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
-
- public class MonkeyInvocationHandler
- implements MethodInterceptor {
- public Object intercept(Object proxy, Method method, Object[] args,
- MethodProxy methodProxy) throws Throwable {
- Object result=null;
- System.out.println("cglib动态代理--开始事务");
- result = methodProxy.invokeSuper(proxy,args);
- System.out.println("cglib动态代理--结束事务");
- return result;
- }
- }
源码下载地址:jdk和cglib实现动态代理