代 理 模 式

什么是代理模式

就像我们的生活中存在许多的中介一样,中介为厂家提供了销售,推广等一系的活。在程序设计中,我们为了让一个类就专注于他应该干的事,我们就引入一个代理类来执行一些额外的操作。通过代理类我们可以做到保护原有的类的方法不被入侵,你无论怎么的折腾代理类,不会该变你原有的类的功能。其次代理类可以增强我们原有类的功能,例如加一个计算该程序运行时长的功能,这个功能显然不是我们原先类期望有的,交给代理类去实现,无疑可以让原先类的代码逻辑更加的清晰。

几种代理模式

静态代理

需要创建一个接口,让代理类和原类都实现这个接口。

一个例子

interface Send{
    void send();
}
class OriginalMessage implements Send{

    @Override
    public void send() {
        System.out.println("send message");
    }
}
class ProxyMessage implements Send{

    private OriginalMessage originalMessage;

    public ProxyMessage() {
    }

    public ProxyMessage(OriginalMessage originalMessage) {
        this.originalMessage = originalMessage;
    }

    @Override
    public void send() {
        //可以去实现一些增强的功能
        System.out.println("do some interest");
        //调用原对象
        originalMessage.send();
        //同样也可以去做一些增强
        System.out.println("continue to dao some interest");
    }
}



public class proxy {
    public static void main(String[] args) {
        OriginalMessage originalMessage=new OriginalMessage();
        ProxyMessage proxyMessage=new ProxyMessage(originalMessage);
        proxyMessage.send();
    }
}

这里我们增强了原对象的send方法。

优点
静态代理实现起来逻辑清晰,代码简单。
缺点
每新增一个要代理的对象,我们就需要一个新的代理对象,不过这个问题我们可以通过多态的方式解决。但是如果我们想要为为我们要代理的对象增加方法呢?这样我们就要修改接口还有我们的代理对象,这样无疑会极大的增加我们的工作量,增加程序出错的风险。而且随着我们要代理的对象方法不断的增加,其代理类会变得越来越臃肿。

动态代理

动态代理内部也分为好几种,有JDK的动态代理以及CGLIB 动态代理(二者的实现原理有一定的区别)。如果你对Spring有一定的了解,那么你对AOP(面向切面编程)就不会陌生。看起来非常高大上的AOP底层原理也不过是一个动态代理。

这里先叙述一下JDK的动态代理。

JDK的动态代理实际就是在运行过程通过反射机制在运行是动态的创建我们的代理对象。

下面是一个使用动态的代理的例子。

一个接口

public interface  UserService {
    void login(String loginName,String passWord) throws InterruptedException;
    void deleteUsers() throws InterruptedException;
    String[] selectUsers() throws InterruptedException;
}

一个接口的实现类

public class UserServiceImpl implements UserService{
    @Override
    public void login(String loginName, String passWord) throws InterruptedException {

        if("admin".equals(loginName)&&"123456".equals(passWord)){
            System.out.println("您登陆成功,欢迎登陆本系统");
        }else{
            System.out.println("您登陆失败,用户名或密码错误");
        }
        Thread.sleep(1000);
    }

    @Override
    public void deleteUsers() throws InterruptedException {


        System.out.println("成功删除了1万个用户");
        Thread.sleep(1000);

        long endTime=System.currentTimeMillis();

    }

    @Override
    public String[] selectUsers() throws InterruptedException {

        System.out.println("查询出了3个用户");
        String[] names={"张三","李四","王五"};
        Thread.sleep(500);
        return names;
    }
}

生成我们代理的方法

public class ProxyUtils {
    //这里用到了多态
    public static UserService creatProxy(UserService userService){
        /*
        * 这里传递的三个参数
        * 第一个参数是当前类的类的加载其
        * 第二个该代理实现的接口列表
        * 第三个是InvocationHandler接口的实现,即我们的调用处理程序,实现我们方法的调用以及增强
        * 
        * */
        UserService userServiceProxy= (UserService) Proxy.newProxyInstance(ProxyUtils.class.getClassLoader(),
                new Class[]{UserService.class},
                new InvocationHandler() {
            
            
            /*
            * 
            * 这个方法需要传递三个参数
            * 
            * proxy用于传递我们的被代理对象
            * method传递要调用的方法
            * args传递要调用方法的参数
            * 
            * */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                        * 我们可以通过方法名来决定我们要增强的方法
                        * 
                        * */
                        if(method.getName().equals("login")||method.getName().equals("deleteUsers")||method.getName().equals("selectUsers")){
                            long starTime=System.currentTimeMillis();
                            //调用Method类的invoke方法,用于调用被代理对象的方法
                            Object result=method.invoke(userService,args);
                            long endTime=System.currentTimeMillis();
                            System.out.println(method.getName()+"方法执行耗时 :"+(endTime-starTime)/1000.0+"s");
                            return result;
                        }else{
                            return method.invoke(userService,args);
                        }
                    }
                });
        return userServiceProxy;
    }
}

测试类

public static void main(String[] args) throws InterruptedException {
        UserService userServiceProxy = ProxyUtils.creatProxy(new UserServiceImpl());
        userServiceProxy.login("admin","123456");
        userServiceProxy.deleteUsers();
        String[] strings = userServiceProxy.selectUsers();
        for (String s:strings) {
            System.out.print(s+" ");
        }
    }

简单概括一下我们使用动态代理的步骤,首先我们创建一个创建动态代理对象的方法,这个方法需要我们传递一个被增强的对象(也可以使用多态,进一步降低了程序的耦合)。之后这个创建方法调用我们的Proxy.newProxyInstance方法创建动态代理,通过重写我们的InvocationHandler接口实现方法的调用和增强。最后只要我们在想要使用这个代理对象是将其创建出来就可以了。

你可能感兴趣的:(java学习,代理模式,java,开发语言)