代理模式网上有一大片一大片的技术帖子,这里不做过多的论述,
下面来一步步从静态代理演化为动态代理。
首先来写一个静态代理的实例:
首先 subject (抽象主题角色):IUserService
package com.soft.day1103.dao;
import com.soft.test.model.User;
import java.util.List;
public interface IUserService {
List<User> 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<User> findAllUser() {
System.out.println("查询到所有用户信息");
return new ArrayList<User>();
}
@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<User> findAllUser() {
pre("findAllUser");
List<User> 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<Customer> findAllCustomer() {
pre("findAllUser");
List<Customer> 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<User> 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里面的代码也做一个整理。
对比两个静态代理类,还是有可以提取出来的部分,excute方法可以再次做拆分处理,放到一个共通处理类里面去。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<User> 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; } }
提取后的代码
然后两个静态代理类,的变化比较大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<User> 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
InvokeHandlerpackage com.soft.day1103.proxy; import java.lang.reflect.Method; public interface InvocationHandler { public Object invoke(Method method, Object[] param); }
UserServiceStaticProxypackage 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代码也有些许调整,这是为了跟jdk动态代理的参数等等一致所做的调整,但是思想是一样的。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<User> 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; } }
这时候如果在测试的话。代码就该这么写了
首先实例化出需要代理的类,将需要代理的类放入到代理逻辑类InvocationHandler中,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设置给静态代理类 这样动态代理模型就初现了。
运行测试:
add开始执行 添加成功 add执行结束 ===================================== findAllUser开始执行 查询到所有用户信息 findAllUser执行结束 ===================================== findUserById开始执行 通过id111 查询到用户信息 findUserById执行结束 ===================================== 依然如初。
看看两个代理类现在的结构逻辑,几乎都是相同的套路,想着如果用代码生成这段代理类不就可以实现动态代理了么?
动态生成代理类,代理逻辑放到一处进行同一处理,就是动态代理的机制。
下面进行动态代理的实现。
首先动态代理类:
Proxy
类生成器 ClassMakerpackage 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; } }
现在进行动态代理的测试。看看是否可以动态实现代理。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; } };