浅谈JAVA动态代理

概念

JAVA动态代理主要用来做方法的增强,在源码不动的情况下,对一些方法实现相应的增强及扩展,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。

动态代理形式

实现动态代理的形式有:JDK动态代理,Cglib代理,Javassist 实现动态代理,ASM实现动态代理等。
详情请参考以下介绍。

创建JDK动态代理

JDK动态代理对象
1)接口代理; 代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能用动态代理!
2)代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型);

代码实现

public class UserDaoDynamicProxy {  
    //维护一个目标对象  
    private Object targetObject;  
    public UserDaoDynamicProxy(Object target){  
        this.targetObject = target;  
    }  
    public Object getProxyInstance(){  
        return Proxy.newProxyInstance(  
                targetObject.getClass().getClassLoader(),  
                targetObject.getClass().getInterfaces(),   
                new InvocationHandler() {  
              
            @Override  
            public Object invoke(Object proxy, Method method, Object[] args)  
                    throws Throwable {   
                System.out.println("动态代理,在开始方法前执行操作");  
                  
                //执行目标对象方法  
                Object returnValue = method.invoke(targetObject, args);  
                  
                System.out.println("动态代理,在开始方法后执行操作");  
                return returnValue;  
            }  
        });  
    }  
}  

Cglib代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
1 ) 需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可;
2)引入功能包后,就可以在内存中动态构建子类
3)代理的类不能为final, 否则报错。
4) 目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法

代码参考

public class UserDaoCglibProxy implements MethodInterceptor{  
    //维护目标对象  
    private Object targetObject;  
    public UserDaoCglibProxy(Object target){  
        this.targetObject = target;  
    }  
      
    //给目标对象创建代理对象  
    public Object getProxyInstance(){  
        //工具类  
        Enhancer enhancer = new Enhancer();  
        //设置父类  
        enhancer.setSuperclass(targetObject.getClass());  
        //设置回调函数  
        enhancer.setCallback(this);  
        //创建子类  
        return enhancer.create();  
    }  
      
    @Override  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy arg3) throws Throwable {  
        System.out.println("我是CGLIB代理对象,在开始方法前执行操作");  
        Object return = method.invoke(targetObject, args);  
        System.out.println("我是CGLIB代理对象,在开始方法后执行操作");  
        return return;  
    }  
      
      
}  

测试类

public class App {  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        IUserDao userDao = new UserDao();  
        IUserDao userDao2 = (IUserDao) new UserDaoDynamicProxy(userDao).getProxyInstance();  
        userDao2.save(); 
        System.out.println("\n------------------------\n");  
        IUserDao userDao3 = (IUserDao) new UserDaoCglibProxy(userDao).getProxyInstance();  
        userDao3.save();  
    }  
}  


总结 : 
在Spring的AOP编程中,  
如果加入容器的目标对象有实现接口,用JDK代理;  
如果目标对象没有实现接口,用Cglib代理;  

Javassist 实现动态代理

javassist 是一款非常优秀的Java 字节码引擎工具,能够在运行时编译、生成Java Class,且可以进行类判断过滤,实现动态代理。

maven依赖

<dependency>
     <groupId>org.javassist</groupId>
     <artifactId>javassist</artifactId>
     <version>3.21.0-GA</version>
 </dependency>

通过javassist.util.proxy.ProxyFactory类来生成代理:

public Object getProxy(Class<?> type) throws IllegalAccessException, InstantiationException {
        ProxyFactory f = new ProxyFactory();
        f.setSuperclass(type);
        f.setFilter(new MethodFilter() {
            public boolean isHandled(Method m) {
                // ignore finalize()
                return !m.getName().equals("finalize");
            }
        });

        Class c = f.createClass();
        MethodHandler mmi= new MethodHandler() {
            public Object invoke(Object self, Method m, Method proceed,
                                 Object[] args) throws Throwable {
                System.out.println("method name: " + m.getName()+" exec");
                return proceed.invoke(self, args);  // execute the original method.
            }
        };
        Object proxy = c.newInstance();
        ((Proxy)proxy).setHandler(mmi);
        return proxy;
    }

ASM实现动态代理

待续!!!.

@Author:zhangjialian

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值