定义
- 为其他对象提供一种代理,以控制对这个对象的访问
- 代理对象在客户端和目标对象之间起到中介作用
适用场景
- 保护目标对象
- 增强目标对象
用于隐藏具体实现类的细节,通常还用于在真实的实现前后增加一部分逻辑。
代理只是一层皮而已,真正的逻辑还是具体实现类来做的。
优点
- 代理模式能将代理对象与真实被调用的目标对象分离
- 一定程度上降低了系统的耦合度,扩展性好
- 保护目标对象
- 增强目标对象
缺点
- 代理模式会造成系统设计中类的数据增加
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
- 增加系统的复杂度
扩展
- 静态代理
- 动态代理
- CGLib代理
- 万次执行情况下,jdk7、8 jdk动态代理比CGLIb快20%左右
静态代理 - Coding
就是在代码中显式指定的代理。
// 具体实现类 伪代码
public class UserServiceImpl implements UserService {
private UserDao userDao;
public Object select(Integer userId){
userDao = new UserDao();
return userDao.select(userId);
}
public Object insert(){
userDao = new UserDao();
return userDao.insert();
}
public Object update(){
return userDao.update();
}
}
// 代理类 伪代码
public class UserServiceProxy {
private UserService userServiceImpl;
public Object select(Integer userId){
// 执行真正的方法前做一些事, 比如切换数据源
DataSourceContext.selectDb(userId % 2);
Object res = userServiceImpl.select(userId);
// 执行真正的方法后做一些事
doSomething();
return res;
}
public Object insert(){
DataSourceContext.selectDb(userId % 2);
Object res = userServiceImpl.insert();
doSomething();
return res;
}
public Object update(){
DataSourceContext.selectDb(userId % 2);
Object res = userServiceImpl.update();
doSomething();
return res;
}
}
动态代理 - Coding
-
JDK的动态代理
-
只能对实现了接口的目标类进行代理,
-
代理类需要实现接口InvocationHandler,实现invoke方法
-
调用Proxy.newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建代理
-
原理:内存中新生成一个类实现目标类的所有接口,重写方法为调用代理类的invoke方法。
public class UserServiceDynamicProxy implements InvocationHandler {
// 被代理的目标类
// 该类实现的接口所有方法都会被代理增强
private Object target;
public Object getInstance(Object target){
this.target = target;
Class<?> cls = target.getClass();
// 核心方法
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod();
Object object = method.invoke(target, args);
argerMethod();
return object;
}
}
public class Test {
public static void main(String[] args) {
UserService userServiceProxy = (UserService) new UserServiceDynamicProxy().getInstance(new UserServiceImpl());
Object select = userServiceProxy.select(1);
}
}
注意:接口定义了A、B方法,接口实现类实现了A、B方法、并自定义了一个C方法,但是接口中并没有C方法,这样情况下创建接口实现类的代理类,是无法代理C方法的。
- CGlib的动态代理
原理:生成一个被代理类的子类,并重写其中的方法。
// org.springframework.cglib.proxy.MethodInterceptor;
public class UserServiceCglibProxy implements MethodInterceptor {
public Object getInstance(Class<?> cls){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invoke(o, objects);
after();
return result;
}
}
如果这个类是final的,这个类无法被继承;又或者类里面的方法是final的,方法无法被重写;
这些情况CGLib是无法代理的。
说白了就是方法包装或者方法增强。
如果帮到你了,请点击右上角给个赞吧!!
学习笔记。内容总结于Geely老师的《Java设计模式精讲 》
欢迎访问我的博客:他和她的猫