20分钟教你理解动态代理和静态代理及应用

什么是代理

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

// 接口功能
interface UserManager{
        void addUser(String id,String name);
        void delUser(String id);
        String findUser(String id);
        void modifyUser(String id,String name);
    }

静态代理

废话不多说,先上代码:

 UserManagerImpl实现接口的方法,并添加子类自己的功能

public class UserManagerImpl implements UserManager {

        @Override
        public void addUser(String userId, String userName) {
            System.out.println("UserManagerImpl.addUser");
        }

        @Override
        public void delUser(String userId) {
            System.out.println("UserManagerImpl.delUser");
        }

        @Override
        public String findUser(String userId) {
            System.out.println("UserManagerImpl.findUser");
            return "张三";
        }

        @Override
        public void modifyUser(String userId, String userName) {
            System.out.println("UserManagerImpl.modifyUser");

        }
    }

创建一个静态代理类,跟子类UserManagerImpl实现同一个接口类UserManager,然后在代理类的构造方法中传入接口类UserManager,这样就可以在子类调用前后添加你想要添加的功能,比如打印日志或者其他操作。

public class UserManagerImplProxy implements UserManager {

        // 目标对象  
        private UserManager userManager;

        // 通过构造方法传入目标对象  
        public UserManagerImplProxy(UserManager userManager) {
            this.userManager = userManager;
        }

        @Override
        public void addUser(String userId, String userName) {
            //添加打印日志的功能  
            //开始添加用户  
            System.out.println("start-->addUser()");

            // 子类实现调用
            userManager.addUser(userId, userName);


            //添加用户成功  
            System.out.println("success-->addUser()");
        }

        @Override
        public void delUser(String userId) {
            //开始添加用户  
            System.out.println("start-->addUser()");
            userManager.delUser(userId);
        }

        @Override
        public String findUser(String userId) {
            //开始添加用户  
            System.out.println("start-->addUser()");
            userManager.findUser(userId);
            return "张三";
        }

        @Override
        public void modifyUser(String userId, String userName) {
            userManager.modifyUser(userId,userName);
        }

    }

客户端:

UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("1111", "张三");

打印结果为:

start-->addUser()
UserManagerImpl.addUser
success-->addUser()

代码分析:

看客户端代码可以知道我们以为使用了静态代理类UserManagerImplProxy,因此给子类UserManagerImpl的addUser()方法添加的日志打印功能,通过打印结果可以看出多了start-->addUser()和success-->addUser()两段文案。

那么如果我们要给子类UserManagerImpl的delUser()等其他方法添加新的打印日志时,是要去修改静态代理中对应的方法内容,这种代码不利于后期扩展和维护,下面要讲到动态代理,可以解决上面遇到这种问题。

动态代理

客户端代码:

UserManager targetObject = new UserManagerImpl();
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器  
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口  
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法  
//根据传入的目标返回一个代理对象 
UserManager userManager = 
(UserManager) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        Object ret = null;

                        System.out.println("satrt-->>");

                        //调用目标方法  被代理类的方法
                        ret = method.invoke(targetObject, args);  
                         /*原对象方法调用后处理日志信息*/
                        System.out.println("success-->>");
                        return ret;
                    }
                });
userManager.addUser("", "");
userManager.findUser("");

打印结果:

satrt-->>
UserManagerImpl.addUser
success-->>
satrt-->>
UserManagerImpl.findUser
success-->>

代码分析:

通过动态代理类:Proxy.newProxyInstance中实现InvocationHandler的invoke方法中添加对代理类的拦截操作,如日志写入等,返回代理类对象。

动态代理可以实现对接口UserManager中全部的方法进行统一的拦截,不需要在每一处代理方法中添加拦截内容。

动态代理是AOP的一种实现。

AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码---解耦。

动手撸一下代码,理解更容易。

猜你喜欢

转载自blog.csdn.net/Qyuewei/article/details/88061295