代理模式-----静态代理到动态代理的演化过程

代理模式网上有一大片一大片的技术帖子,这里不做过多的论述,

代理模式传送门

下面来一步步从静态代理演化为动态代理。

首先来写一个静态代理的实例:

首先 subject (抽象主题角色):IUserService

package com.soft.day1103.dao;

import com.soft.test.model.User;

import java.util.List;

public interface IUserService {

    List findAllUser();

    User findUserById(String id);

    int add(User user);
}

realSubject真实主题角色 UserServiceImpl

package com.soft.day1103.dao.impl;

import com.soft.day1103.dao.IUserService;
import com.soft.test.model.User;

import java.util.ArrayList;
import java.util.List;

public class UserServiceImpl implements IUserService {
    @Override
    public List findAllUser() {
        System.out.println("查询到所有用户信息");

        return new ArrayList();
    }

    @Override
    public User findUserById(String id) {
        System.out.println("通过id" + id + " 查询到用户信息");
        return new User();
    }

    @Override
    public int add(User user) {
        System.out.println("添加成功");
        return 0;
    }
}
proxy代理主题角色 UserServiceStaticProxy

package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.day1103.dao.impl.UserServiceImpl;
import com.soft.test.model.User;

import java.util.List;

public class UserServiceStaticProxy implements IUserService {

    // 维持真是对象的引用
    private UserServiceImpl userService = new UserServiceImpl();

    /*做一些代理操作逻辑  start*/
    /**
     * 方法执行前的逻辑处理
     * @param methodName
     */
    private void pre(String methodName){
        System.out.println(methodName + "开始执行");
    }

    /**
     * 方法之后结束后的逻辑处理
     * @param methodName
     */
    private void after(String methodName){
        System.out.println(methodName + "执行结束");
    }
    /*做一些代理操作  end*/

    @Override
    public List findAllUser() {

        pre("findAllUser");
        List list = userService.findAllUser();
        after("findAllUser");
        return list;
    }

    @Override
    public User findUserById(String id) {
        pre("findUserById");
        User user = userService.findUserById(id);
        after("findUserById");
        return user;
    }

    @Override
    public int add(User user) {
        pre("add");
        int addRes = userService.add(user);
        after("add");
        return addRes;
    }
}

实体类:(测试用的没有意义)

package com.soft.day1103.model;

public class User {


    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

测试代理类

package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.test.model.User;
import org.junit.Test;

public class UserServiceStaticProxyTest {

    private IUserService userService = new UserServiceStaticProxy();

    @Test
    public void findAllUser() throws Exception {
        userService.findAllUser();
        print();
    }

    @Test
    public void findUserById() throws Exception {
        userService.findUserById("111");
        print();
    }

    @Test
    public void add() throws Exception {
        userService.add(new User());
        print();
    }

    private void print(){
        System.out.println("=====================================");
    }
}

测试结果:


add开始执行
添加成功
add执行结束
=====================================
findAllUser开始执行
查询到所有用户信息
findAllUser执行结束
=====================================
findUserById开始执行
通过id111 查询到用户信息
findUserById执行结束
=====================================

结果可以看出,每次执行真是对象的方法的前后都会插入代理逻辑,这里就说明代理成功了。
但是静态代理有个缺点:

每个真实主题角色都必须有一个代理类。也就是如果再有一个主题角色,就必须再有一个代理类。会导致类的膨胀。

比如现在有个 CustomerServiceImpl 需要代理,这个时候就需要在弄一个代理类出来。

package com.soft.day1103.proxy;

import com.soft.day1103.dao.ICustomerService;
import com.soft.day1103.dao.impl.CustomerServiceImpl;
import com.soft.day1103.model.Customer;

import java.util.List;

public class CustomerServiceStaticProxy implements ICustomerService {

    // 维持真是对象的引用
    private ICustomerService userService = new CustomerServiceImpl();

    /*做一些代理操作逻辑  start*/

    /**
     * 方法执行前的逻辑处理
     *
     * @param methodName
     */
    private void pre(String methodName) {
        System.out.println(methodName + "开始执行");
    }

    /**
     * 方法之后结束后的逻辑处理
     *
     * @param methodName
     */
    private void after(String methodName) {
        System.out.println(methodName + "执行结束");
    }
    /*做一些代理操作  end*/

    @Override
    public List findAllCustomer() {

        pre("findAllUser");
        List list = userService.findAllCustomer();
        after("findAllUser");
        return list;
    }

    @Override
    public Customer findUserById(String id) {
        pre("findUserById");
        Customer user = userService.findUserById(id);
        after("findUserById");
        return user;
    }

    @Override
    public int add(Customer user) {
        pre("add");
        int addRes = userService.add(user);
        after("add");
        return addRes;
    }
}
通过观察两个静态代理类,可以发现优化项,每个方法执行前后的代码重复,可以提成公共部分,但是由于执行的方法不同,这时候可以想到用反射来执行方法,然后反射执行方法前加上代理逻辑处理。通过优化后的代码:

 
  
package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.day1103.dao.impl.UserServiceImpl;
import com.soft.test.model.User;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class UserServiceStaticProxy implements IUserService {

    // 维持真是对象的引用
    private UserServiceImpl userService = new UserServiceImpl();

    /*做一些代理操作逻辑  start*/
    /**
     * 方法执行前的逻辑处理
     * @param methodName
     */
    private void pre(String methodName){
        System.out.println(methodName + "开始执行");
    }

    /**
     * 方法之后结束后的逻辑处理
     * @param methodName
     */
    private void after(String methodName){
        System.out.println(methodName + "执行结束");
    }
    /*做一些代理操作  end*/

    @Override
    public List findAllUser() {
        return (List)excute("findAllUser",new Object[]{},null);
    }

    @Override
    public User findUserById(String id) {
        return (User)excute("findUserById",new Object[]{id},String.class);
    }

    @Override
    public int add(User user) {

        return (int)excute("add",new Object[]{user},User.class);
    }


    private Object excute(String methodName, Object[] param, Class... params){
        Object obj = null;
        try {
            Method method = userService.getClass().getMethod(methodName, params);
            pre(methodName);
            obj = method.invoke(userService,param);
            after(methodName);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return obj;
    }

}
这样优化后在进行测试。
 
  
add开始执行
添加成功
add执行结束
=====================================
findAllUser开始执行
查询到所有用户信息
findAllUser执行结束
=====================================
findUserById开始执行
通过id111 查询到用户信息
findUserById执行结束
=====================================
然后将CustomerServiceStaticProxy里面的代码也做一个整理。
 
  
package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.day1103.dao.impl.UserServiceImpl;
import com.soft.test.model.User;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class UserServiceStaticProxy implements IUserService {

    // 维持真是对象的引用
    private UserServiceImpl userService = new UserServiceImpl();

    /*做一些代理操作逻辑  start*/
    /**
     * 方法执行前的逻辑处理
     * @param methodName
     */
    private void pre(String methodName){
        System.out.println(methodName + "开始执行");
    }

    /**
     * 方法之后结束后的逻辑处理
     * @param methodName
     */
    private void after(String methodName){
        System.out.println(methodName + "执行结束");
    }
    /*做一些代理操作  end*/

    @Override
    public List findAllUser() {
        return (List)excute("findAllUser",new Object[]{},null);
    }

    @Override
    public User findUserById(String id) {
        return (User)excute("findUserById",new Object[]{id},String.class);
    }

    @Override
    public int add(User user) {

        return (int)excute("add",new Object[]{user},User.class);
    }


    private Object excute(String methodName, Object[] param, Class... params){
        Object obj = null;
        try {
            Method method = userService.getClass().getMethod(methodName, params);
            pre(methodName);
            obj = method.invoke(userService,param);
            after(methodName);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return obj;
    }

}
对比两个静态代理类,还是有可以提取出来的部分,excute方法可以再次做拆分处理,放到一个共通处理类里面去。 
  
提取后的代码
 
  
package com.soft.day1103.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class InvokeHandler {

    /**
     * 代理对象的引用
     */
    private Object obj;

    public InvokeHandler(Object obj) {
        this.obj = obj;
    }

    /*做一些代理操作逻辑  start*/
    /**
     * 方法执行前的逻辑处理
     * @param methodName
     */
    private void pre(String methodName){
        System.out.println(methodName + "开始执行");
    }

    /**
     * 方法之后结束后的逻辑处理
     * @param methodName
     */
    private void after(String methodName){
        System.out.println(methodName + "执行结束");
    }
    /*做一些代理操作  end*/


    public Object excute(String methodName, Object[] param, Class... params){
        try {
            Method method = obj.getClass().getMethod(methodName, params);
            pre(methodName);
            obj = method.invoke(obj,param);
            after(methodName);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return obj;
    }

}
然后两个静态代理类,的变化比较大 
  
 
  
package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.day1103.dao.impl.UserServiceImpl;
import com.soft.test.model.User;

import java.util.List;

public class UserServiceStaticProxy implements IUserService {

    // 维持真是对象的引用
    private UserServiceImpl userService = new UserServiceImpl();
    private InvokeHandler handler = new InvokeHandler(userService);

    @Override
    public List findAllUser() {
        return (List) handler.excute("findAllUser", new Object[]{}, null);
    }

    @Override
    public User findUserById(String id) {
        return (User) handler.excute("findUserById", new Object[]{id}, String.class);
    }

    @Override
    public int add(User user) {
        return (int) handler.excute("add", new Object[]{user}, User.class);
    }
}
看着是否清爽多了,这样代理逻辑单独封装,代理类对代理逻辑进行调用。
但是这样还有不爽的地方,那就是代码还比较死。如果代理处理逻辑有变化,或者类名有变化等,静态代理类就需要修改。
这时候想到用接口类替代InvokeHandler,然后需要代理的类交给代理逻辑类(InvokeHandler)进行处理。
这里这个接口名字就用jdk动态代理里面的名字InvocationHandler
 
  
package com.soft.day1103.proxy;

import java.lang.reflect.Method;

public interface InvocationHandler {

    public Object invoke(Method method, Object[] param);
}
InvokeHandler
 
  
package com.soft.day1103.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class InvokeHandler implements InvocationHandler{

    /**
     * 代理对象的引用
     */
    private Object obj;

    public InvokeHandler(Object obj) {
        this.obj = obj;
    }

    /*做一些代理操作逻辑  start*/
    /**
     * 方法执行前的逻辑处理
     * @param methodName
     */
    private void pre(String methodName){
        System.out.println(methodName + "开始执行");
    }

    /**
     * 方法之后结束后的逻辑处理
     * @param methodName
     */
    private void after(String methodName){
        System.out.println(methodName + "执行结束");
    }
    /*做一些代理操作  end*/

    @Override
    public Object invoke(Method method, Object[] param) {
        Object object = null;
        try {
            pre(method.getName());
            object = method.invoke(obj,param);
            after(method.getName());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return object;
    }
}
UserServiceStaticProxy
 
  
package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.test.model.User;

import java.lang.reflect.Method;
import java.util.List;

public class UserServiceStaticProxy implements IUserService {

    // 维持真是对象的引用
    private InvocationHandler handler;

    public UserServiceStaticProxy(InvocationHandler handler) {
        this.handler = handler;
    }

    @Override
    public List findAllUser() {
        return (List) excute("findAllUser", new Object[]{}, null);
    }

    @Override
    public User findUserById(String id) {
        return (User) excute("findUserById", new Object[]{id}, String.class);
    }

    @Override
    public int add(User user) {
        return (int) excute("add", new Object[]{user}, User.class);
    }

    private Object excute(String methodName, Object[] param, Class... params) {
        Object obj = null;
        try {
            Method method = IUserService.class.getMethod(methodName, params);
            obj = handler.invoke(method, param);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return obj;
    }
}
注意下UserServiceStaticProxy代码也有些许调整,这是为了跟jdk动态代理的参数等等一致所做的调整,但是思想是一样的。
这时候如果在测试的话。代码就该这么写了
 
  
package com.soft.day1103.proxy;

import com.soft.day1103.dao.IUserService;
import com.soft.day1103.dao.impl.UserServiceImpl;
import com.soft.test.model.User;
import org.junit.Test;

public class UserServiceStaticProxyTest {
    // 动态代理快成功了,这里就这样写了。
    private IUserService userServicesss = new UserServiceImpl();
    InvocationHandler handler = new InvokeHandler(userServicesss);
    private IUserService userService = new UserServiceStaticProxy(handler);

    @Test
    public void findAllUser() throws Exception {
        userService.findAllUser();
        print();
    }

    @Test
    public void findUserById() throws Exception {
        userService.findUserById("111");
        print();
    }

    @Test
    public void add() throws Exception {
        userService.add(new User());
        print();
    }

    private void print(){
        System.out.println("=====================================");
    }
}
首先实例化出需要代理的类,将需要代理的类放入到代理逻辑类InvocationHandler中,
最后InvocationHandler设置给静态代理类
这样动态代理模型就初现了。
运行测试:
 
  
add开始执行
添加成功
add执行结束
=====================================
findAllUser开始执行
查询到所有用户信息
findAllUser执行结束
=====================================
findUserById开始执行
通过id111 查询到用户信息
findUserById执行结束
=====================================
 依然如初。
看看两个代理类现在的结构逻辑,几乎都是相同的套路,想着如果用代码生成这段代理类不就可以实现动态代理了么?
动态生成代理类,代理逻辑放到一处进行同一处理,就是动态代理的机制。

下面进行动态代理的实现。
首先动态代理类:
Proxy
 
  
package com.soft.day1103.proxy;

import com.soft.day1103.util.ClassMaker;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Proxy {

    public static Object newProxyInstance(Class cla, InvocationHandler handler){
        Class createClass = ClassMaker.createProxyClass(cla);
        try {
            Constructor constructor = createClass.getConstructor(InvocationHandler.class);
            return constructor.newInstance(handler);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}
类生成器 ClassMaker
 
  
package com.soft.day1103.util;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class ClassMaker {

    private static final String IMPORT = "import ";
    private static final String FENHAO = ";\n";
    private static final String CLASS_PUBLIC = "public class ";
    private static final String IMPLEMANT = " implements ";
    private static final String QIANKUOHAO = "{";
    private static final String HOUKUOHAO = "}";
    private static final String PRIVATE_ = "private ";
    private static final String PUBLIC = "public ";
    private static final String NEWLINE = "\n";

    public static Class classLoad(String classInfo, String className) {
        try {

            FileOutputStream fo = new FileOutputStream("D:\\myproject\\mybatisLearn\\src\\main\\java\\com\\soft\\day1103\\proxy\\" + className + ".java");
            fo.write(classInfo.getBytes());
            fo.flush();
            Thread.sleep(1000);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Class retu = null;
        try {
            retu = Class.forName("com.soft.day1103.proxy." + className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return retu;
    }

    public static Class createProxyClass(Class targetObject) {
        StringBuffer sb = new StringBuffer();
        sb.append("package com.soft.day1103.proxy;");
        sb.append("import java.lang.reflect.Method;");
        String interfaceName = targetObject.getSimpleName();
        sb.append("import " + targetObject.getPackage().getName() +"."+ interfaceName + ";");
        Method[] methods = targetObject.getMethods();
        for (Method method : methods) {
            Class returnType = method.getReturnType();
            if(needImport(returnType)){
                sb.append("import " + returnType.getPackage().getName() +"."+ returnType.getSimpleName() + ";");
            }
        }
        // 生成类开始
        sb.append(" public class " + interfaceName + "Proxy implements " + interfaceName + " {");

        // 维持真实对象的引用
        sb.append("private InvocationHandler handler;");

        // 构造函数
        sb.append("public " + interfaceName + "Proxy(InvocationHandler handler) {");
        sb.append("this.handler = handler;}");

        // 生成代理方法
        for (Method method : methods) {
            Class returnType = method.getReturnType();
            Class[] methodParamClass = method.getParameterTypes();
            sb.append("@Override" + NEWLINE);
            sb.append(PUBLIC + returnType.getName() + " " + method.getName() + "(");

            // 反射方法参数
            StringBuffer refMethodParamters = new StringBuffer();
            int index = 0;
            // 方法参数
            StringBuffer methodParams = new StringBuffer();
            // 获取反射方法参数 class
            StringBuffer refMethodClasses = new StringBuffer();
            for (Class methodParam : methodParamClass) {
                String paramName = methodParam.getName();
                methodParams.append(paramName + " param" + index + ",");
                refMethodParamters.append(" param" + index + ",");
                String[] arr = paramName.split("\\.");
                refMethodClasses.append(arr[arr.length - 1] + ".class" + ",");
                index++;
            }
            if (methodParams.length() > 0) {
                sb.append(methodParams.substring(0, methodParams.toString().length() - 1));
            }
            sb.append(")" + QIANKUOHAO + NEWLINE);
            if (refMethodParamters.length() > 0) {
                sb.append("Object[] objects = { " + refMethodParamters.substring(0, refMethodParamters.length() - 1) + "}" + FENHAO + NEWLINE);
            } else {
                sb.append("Object[] objects = new Object[" + methodParamClass.length + "]" + FENHAO + NEWLINE);
            }
            if (needReturn(returnType)) {
                sb.append("return (" + returnType.getName() + ")");
            }
            String classes = null;
            if(refMethodClasses.length() > 0){
                classes = refMethodClasses.substring(0,refMethodClasses.length()-1);
            }
            sb.append("excute(\"" + method.getName() + "\" , objects , " + classes + ")" + FENHAO + NEWLINE);
            sb.append(HOUKUOHAO + NEWLINE);
        }


        // 生成反射方法
        sb.append(" private Object excute(String methodName, Object[] param, Class... params) {");
        sb.append("Object obj = null;");
        sb.append("try {");
        sb.append("Method method = " + interfaceName + ".class.getMethod(methodName, params);");
        sb.append("obj = handler.invoke(method, param);");
        sb.append("} catch (NoSuchMethodException e) {");
        sb.append("  e.printStackTrace();}");

        sb.append("return obj;}");
        sb.append(HOUKUOHAO + FENHAO + NEWLINE);
        return classLoad(sb.toString(), interfaceName + "Proxy");

    }

    private static boolean needImport(Class tar) {
        return "voidStringintdoublelangfloatbooleanbytecharshort".indexOf(tar.getSimpleName()) == -1;
    }

    private static boolean needReturn(Class tar) {
        return "void".indexOf(tar.getSimpleName()) == -1;
    }


}
现在进行动态代理的测试。看看是否可以动态实现代理。
注意:
由于仅仅是模仿,没办法生成java代理类之后直接放入内存。所以需要弄两次,第一次仅仅是生成java代码。然后才可以将其读入内存。

下面进行测试:
先来动态代理 IUserService
 
  
 @Test
    public void testproxy() throws Exception {
        IUserService iUserService = (IUserService)Proxy.newProxyInstance(IUserService.class, handler);
        iUserService.add(new User());
        print();
    }
测试结果:
add开始执行
添加成功
add执行结束
=====================================
将接口替换成 ICustomerService
 
  
    @Test
    public void testproxy() throws Exception {
        ICustomerService iUserService = (ICustomerService)Proxy.newProxyInstance(ICustomerService.class, handler);
        iUserService.add(new Customer());
        print();
    }
测试结果:
add开始执行
添加成功
add执行结束
=====================================
 
  
完了静态代理演化为动态代理了。希望明白了。

生成的两个代理类的代码:
 
  
package com.soft.day1103.proxy;

import java.lang.reflect.Method;

import com.soft.day1103.dao.IUserService;

import java.util.List;

import com.soft.test.model.User;

public class IUserServiceProxy implements IUserService {
    private InvocationHandler handler;

    public IUserServiceProxy(InvocationHandler handler) {
        this.handler = handler;
    }

    @Override
    public int add(com.soft.test.model.User param0) {
        Object[] objects = {param0};

        return (int) excute("add", objects, User.class);

    }

    @Override
    public java.util.List findAllUser() {
        Object[] objects = new Object[0];

        return (java.util.List) excute("findAllUser", objects, null);

    }

    @Override
    public com.soft.test.model.User findUserById(java.lang.String param0) {
        Object[] objects = {param0};

        return (com.soft.test.model.User) excute("findUserById", objects, String.class);

    }

    private Object excute(String methodName, Object[] param, Class... params) {
        Object obj = null;
        try {
            Method method = IUserService.class.getMethod(methodName, params);
            obj = handler.invoke(method, param);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return obj;
    }
};

package com.soft.day1103.proxy;

import com.soft.day1103.dao.ICustomerService;
import com.soft.day1103.model.Customer;

import java.lang.reflect.Method;

public class ICustomerServiceProxy implements ICustomerService {
    private InvocationHandler handler;

    public ICustomerServiceProxy(InvocationHandler handler) {
        this.handler = handler;
    }

    @Override
    public int add(com.soft.day1103.model.Customer param0) {
        Object[] objects = {param0};

        return (int) excute("add", objects, Customer.class);

    }

    @Override
    public java.util.List findAllCustomer() {
        Object[] objects = new Object[0];

        return (java.util.List) excute("findAllCustomer", objects, null);

    }

    @Override
    public com.soft.day1103.model.Customer findUserById(java.lang.String param0) {
        Object[] objects = {param0};

        return (com.soft.day1103.model.Customer) excute("findUserById", objects, String.class);

    }

    private Object excute(String methodName, Object[] param, Class... params) {
        Object obj = null;
        try {
            Method method = ICustomerService.class.getMethod(methodName, params);
            obj = handler.invoke(method, param);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return obj;
    }
};



你可能感兴趣的:(设计模式)