1. 代理模式(Proxy Pattern)
代理模式(Proxy Pattern) ,给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。这种也是静态代理
代理模式包含如下角色:
Subject: 抽象主体角色(抽象类或接口)
Proxy: 代理主体角色(代理对象类)
RealSubject: 真实主体角色(被代理对象类)
2. 静态代理
- 静态代理就是装饰器模式
- 装饰器模式是代理模式的一种
Subject: 抽象主体角色(抽象类或接口)
/**
* 抽象主体 被代理角色
*/
public interface ManTikTok {
void tiktok();
}
Proxy: 代理主体角色(代理对象类)
/**
* 代理一般和被代理对象属于同一个接口
* 静态代理就是装饰器模式
* 装饰器模式是代理模式的一种
*/
public class TiktokProxy implements ManTikTok{
//被代理对象
private MiTikTok miTikTok;
public TiktokProxy(MiTikTok miTikTok) {
this.miTikTok = miTikTok;
}
@Override
public void tiktok() {
System.out.println("增强功能");
miTikTok.tiktok();
}
}
RealSubject: 真实主体角色(被代理对象类)
/**
* subject 主体
*
*/
public class MiTikTok implements ManTikTok{
@Override
public void tiktok() {
System.out.println("雷军正在直播");
}
}
测试
public static void main(String[] args) {
TiktokProxy tiktokProxy = new TiktokProxy(new MiTikTok());
tiktokProxy.tiktok();
}
3. JDK动态代理
利用JDK动态代理 反射增强
Subject: 抽象主体角色(抽象类或接口)
/**
* 抽象主体 被代理角色
*/
public interface ManTikTok {
void tiktok();
}
public interface SellTiktok {
void send();
}
Proxy: 代理主体角色(代理对象类)
public class JdkTiktokProxy<T> implements InvocationHandler {
private T target;
//接受被代理对象
public JdkTiktokProxy(T target) {
this.target = target;
}
/**
* 获取被代理对象的 代理对象
*
* @param t
* @param <T>
* @return
*/
public static <T> T getProxy(T t) {
/**
* ClassLoader loader, 当前被代理的类加载器
* Class<?>[] interfaces, 当前被代理对象所实现的所有接口 必须要有接口 如果无则会报异常 代理对象无法创建
* InvocationHandler h 当前被代理对象执行目标方法的时候我们使用h可以定义拦截增强方法
*/
Object o = Proxy.newProxyInstance(t.getClass().getClassLoader(),
t.getClass().getInterfaces(),
new JdkTiktokProxy<>(t)
);
return (T) o;
}
/**
* 定义目标方法的拦截逻辑:每个方法都会进来的
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//反射执行
System.out.println("被代理对象原身方法被执行");
Object invoke = method.invoke(target, args);
System.out.println("返回值" + invoke);
return invoke;
}
}
RealSubject: 真实主体角色(被代理对象类)
/**
* subject 主体
*
*/
public class MiTikTok implements ManTikTok,SellTiktok {
@Override
public void tiktok() {
System.out.println("雷军正在直播");
}
@Override
public void send() {
System.out.println("卖货 只要999");
}
public void self(){
System.out.println("自身方法");
}
}
测试方法
/**
* 动态代理模式
* JDK要求被代理对象必须要有接口
*
*/
public class MainTest {
public static void main(String[] args) {
ManTikTok miTikTok = new MiTikTok();
ManTikTok proxy = JdkTiktokProxy.getProxy(miTikTok);
proxy.tiktok();
System.out.println("---------------");
SellTiktok sellTikTok = (SellTiktok)miTikTok;
SellTiktok proxy1 = JdkTiktokProxy.getProxy(sellTikTok);
proxy1.send(); //只能调用某个接口的实现方法
System.out.println("---------------");
MiTikTok miTikTok1 = (MiTikTok) miTikTok;
//无法代理对象本类自己的方法 proxy只能转成接口类
// MiTikTok proxy2 = JdkTiktokProxy.getProxy(miTikTok1);
miTikTok1.self();
System.out.println(Arrays.asList(miTikTok1.getClass().getInterfaces()));
}
}
4. cglib动态代理
在pom.xml
导入cglib依赖
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
cglib不依赖于接口代理反射,他会根据代理对象去继承一个新类,从而代理这个对象。
Proxy: 代理主体角色(代理对象类)
public class CglibProxy {
//为任意对象创建代理
public static <T> T crateProxy(T t) {
//1. 创建一个增强器
Enhancer enhancer = new Enhancer();
//2.设置增强哪个类的功能 增强器为这个类动态创建一个子类
enhancer.setSuperclass(t.getClass());
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method //为了能获取原方法的一些原数据信息
, Object[] objects, MethodProxy methodProxy) throws Throwable {
//编写拦截逻辑
System.out.println("cglib 代理");
//当前方法的信息
// method.getAnnotatedReturnType();
//目标方法进行执行 原对象的方法
Object invoke = methodProxy.invokeSuper(o, objects);
return invoke;
}
});
//创建代理对象
Object o = enhancer.create();
return (T)o;
}
}
RealSubject: 真实主体角色(被代理对象类)
/**
* subject 主体
*
*/
public class MiTikTok {
public void self(){
System.out.println("自身方法");
}
}
测试类
public class CglibTest {
public static void main(String[] args) {
//原对象都不用new
MiTikTok miTikTok = new MiTikTok();
MiTikTok proxy = CglibProxy.crateProxy(miTikTok);
proxy.self();
}
}
5. 应用场景
MyBatis的mapper到底是什么?怎么生成的?
动态代理
UserMapper、CityMapper,mybatis帮我们写实现MapperProxy
Alibaba Seata的DataSourceProxy是什么?
DruidDataSource存在的Proxy模式
- 监控链…