如何实现JDK动态代理?

代理模式:

代理模式给某个对象提供了一个代理对象,并由代理对象控制对原对象的引用。

代理分为静态代理和动态代理。

为何用代理?

不用代理时,在写实现接口类UserManagerImpl的时候代码是这样写的:

public void addUser(String userId, String userName) {
        System.out.println("start-->>addUser() userId-->>" + userId);
        try {
            System.out.println("UserManagerImpl.addUser() userId-->>" + userId);

            System.out.println("success-->>addUser()");
        }catch(Exception e) {
            e.printStackTrace();
            System.out.println("error-->>addUser()");
            throw new RuntimeException();
        }   
    }

我们的需求是调用每个像addUser()这样的方法都需要加上日志记录,开始需要记录,成功需要记录,错误也需要记录,这样如果该类中方法很多的话,在维护的时候就会很难,为了遵守OCP,我们索性抽出一个代理类,代真正的实现类去执行一些操作,所以就用到了代理模式。

第一版重构:

使用静态代理:
调用流程图:
这里写图片描述

代理类部分代码实现:

public class UserManagerImplProxy implements UserManager {

    private UserManager userManager;

    public UserManagerImplProxy(UserManager userManager) {
        this.userManager = userManager;
    }

    public void addUser(String userId, String userName) {
        try {
            System.out.println("start-->>addUser() userId-->>" + userId);
            userManager.addUser(userId, userName);
            System.out.println("success-->>addUser()");
        }catch(Exception e) {
            e.printStackTrace();
            System.out.println("error-->>addUser()");
        }   
    }
}

静态代理解决了OCP的问题,但同样存在其他问题:
1、如果系统足够大,需要建立大量的代理类
2、重复代码出现在各个地方,违背原则:重复代码最好不要出现多次。

第二版重构:

使用动态代理:
调用流程图:
这里写图片描述

代码实现:
Client类:

public static void main(String[] args) {
        LogHandler logHandler = new LogHandler();
        //userManager是一个代理对象
        UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
        //userManager.addUser("0001", "张三");
        //userManager.delUser("0001");
        String name = userManager.findUser("0001");
        System.out.println("Client.main() --- " + name);
    }

LogHandler类:

public class LogHandler implements InvocationHandler {

    private Object targetObject;
    //this相当于一个代理对象
    public Object newProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                               targetObject.getClass().getInterfaces(), this);
    }
    //每次调用该方法都会动态添加日志记录
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("start-->>" + method.getName());
        for (int i=0; i<args.length; i++) {
            System.out.println(args[i]);
        }
        Object ret = null;
        try {
            //调用目标方法,方法有返回值,ret不为空;方法无返回值,ret默认null;该method为findUser(),根据Client传过来,动态识别
            ret = method.invoke(targetObject, args);
            System.out.println("success-->>" + method.getName()); 
        }catch(Exception e) {
            e.printStackTrace();
            System.out.println("error-->>" + method.getName());
            throw e;
        }
        return ret;
    }

}

动态代理:在运行时创建代理类,JDK动态代理只能对实现了接口的类进行代理,意思是,用LogHandler代理UserManagerImpl,前提是UserManagerImpl必须实现UserManager接口。

cglib代理

如果没有实现接口,就要用到cglib代理了

public class CglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class<?> clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        Object object = enhancer.create();
        return object;
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println(o.getClass().getName() + "." + method.getName());

        //执行父类对应方法
        final Object result = methodProxy.invokeSuper(o, objects);

        System.out.println("执行结束");

        return result;
    }

    public static void main(String[] args) {

        CglibProxy proxy = new CglibProxy();
        Person person = (Person) proxy.getProxy(Person.class);
        System.out.println(person.getClass().getName());
        person.study();

    }
}

比较静态代理和动态代理

这里写图片描述

动态代理:实现JDK里的InvocationHandler接口得invoke(),但注意的是代理的接口,也就是你的业务必须实现接口,通过Proxy的newProxyInstance得到代理对象。

感谢您的阅读!

评论 60
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值