代理模式(Proxy)对原有类进行功能增强或替换。代理模式又分为静态代理和动态代理。静态代理又跟装饰器模式类似
一个普通的用户service服务案例
/**
* @description: 用户服务
* @author: jiang
*/
public interface IUserService {
/**
* 添加
* @param name
* @return
*/
boolean insert(String name);
/**
* 获取用户名
* @return
*/
String getUser();
/**
* 获取所有用户
* @return
*/
List<String> listUser();
}
/**
* @description: 用户服务实现
* @author: jiang
*/
public class UserService implements IUserService{
@Override
public boolean insert(String name) {
System.out.println("insert");
return true;
}
@Override
public String getUser() {
System.out.println("getUser");
return "zhangsan";
}
@Override
public List<String> listUser() {
System.out.println("listUser");
return Arrays.asList("zhangsan","wangwu");
}
}
public static void main(String[] args) {
IUserService userService = new UserService();
userService.insert("test");
userService.getUser();
userService.listUser();
}
结果:
insert
getUser
listUser
现在要求在所有请求方法里加上日志输出,打印出请求参数和响应结果,怎么处理呢?
1.在每个方法上打印出参数和响应,如果日志输出的格式需要变更,方法又很多,手都要改麻
JDK动态代理
/**
* @description: Jdk动态代理实现用户服务日志打印
* @author: jiang
*/
public class UserServiceJdkProxy<T> implements InvocationHandler {
//需要代理的对象
private T obj;
public UserServiceJdkProxy(T obj) {
this.obj = obj;
}
public static <T> T getProxyInstance(T t){
return (T)(Proxy.newProxyInstance(t.getClass().getClassLoader(),t.getClass().getInterfaces(),new UserServiceJdkProxy(t)));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(MessageFormat.format("输出日志,方法名:{0},参数:{1}",method.getName(),Arrays.asList(Optional.ofNullable(args).orElse(new Object[]{}))));
Object invoke = method.invoke(obj, args);
System.out.println(MessageFormat.format("输出日志,执行结果:{0}",invoke));
return invoke;
}
}
public static void main(String[] args) {
IUserService userService = new UserService();
IUserService proxyInstance = UserServiceJdkProxy.getProxyInstance(userService);
proxyInstance.insert("test");
proxyInstance.getUser();
proxyInstance.listUser();
}
结果:
输出日志,方法名:insert,参数:[test]
insert
输出日志,执行结果:true
输出日志,方法名:getUser,参数:[]
getUser
输出日志,执行结果:zhangsan
输出日志,方法名:listUser,参数:[]
listUser
输出日志,执行结果:[zhangsan, wangwu]
优点:不用每个类都写一个Proxy代理类,Jdk动态生成
缺点:需要代理的对象必须实现至少一个 interface接口。如果动态代理一个没实现接口的类呢?
Cglib动态代理
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
/**
* @description: Cglib动态代理实现用户服务日志打印
* @author: jiang
*/
public class UserServiceCglibProxy<T> implements MethodInterceptor {
public static <T> T getProxyInstance(T t){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(t.getClass());
enhancer.setCallback(new UserServiceCglibProxy());
return (T)(enhancer.create());
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(MessageFormat.format("输出日志,方法名:{0},参数:{1}",method.getName(),Arrays.asList(Optional.ofNullable(args).orElse(new Object[]{}))));
Object invoke = proxy.invokeSuper(obj, args);
System.out.println(MessageFormat.format("输出日志,执行结果:{0}",invoke));
return invoke;
}
}
public static void main(String[] args) {
IUserService userService = new UserService();
IUserService proxyInstance = UserServiceCglibProxy.getProxyInstance(userService);
proxyInstance.insert("test");
proxyInstance.getUser();
proxyInstance.listUser();
}
结果:
输出日志,方法名:insert,参数:[test]
insert
输出日志,执行结果:true
输出日志,方法名:getUser,参数:[]
getUser
输出日志,执行结果:zhangsan
输出日志,方法名:listUser,参数:[]
listUser
输出日志,执行结果:[zhangsan, wangwu]