用一个小故事模拟Spring Aop(二): 代理工厂jdk和cglib
jdk与cglib
承接上文
上文
代理公司
生成售货员
的前提是冰淇淋机必须有接口
(jdk动态代理,只能对有接口的类生成代理)。为了解决这个问题,代理公司只能技术革新了
代理公司引入新技术叫cglib,可以再没有接口
的情况下生成代理,公司分成两个部门,一个还是用老jdk技术,一个使用新cglib技术,代理公司
也升级为代理工厂
,并设置一个调度人员
是否有接口
来交给不同的部门处理。
代理工厂
又设置一个职位专门负责收集需求(需求人员
),发给调度人员
,调度人员
再根据需求人员
提供的信息把工作分配给不同的部门(同时下发需求配置给工作部门)。
画个图梳理下整个过程:
首先来用代码模拟下这个需求整理需求人员
/**
* @Author wmf
* @Date 2022/1/19 17:05
* @Description 需求人员
*/
public class ProxyConfig {
/**
* 附加工作列表
*/
List interceptors = new ArrayList<>();
/**
* 绑定的机器
*/
Object target;
/**
* 是否有规范(是否有实现的接口)
*/
Boolean isImpl;
/**
* 设置拦截计划
* @param interceptor
*/
public void addInterceptor(MethodInterceptor interceptor) {
this.interceptors.add(interceptor);
}
/**
* 获取拦截计划
*/
List getInterceptors() {
return interceptors;
}
/**
* 绑定机器
* @param target
*/
public void setTarget(Object target) {
this.target = target;
}
/**
* 设置是否有规范(是否有实现的接口)
* @param impl
*/
public void setImpl(Boolean impl) {
isImpl = impl;
}
}
可以告诉需求人员
绑定的机器,可以设置拦截计划列表,是否有规范(其实可以根据target自动识别,但是懒着写了,都配吧)
然后之前的ProxyCompany改成jdk动态部门
/**
* @Author wmf
* @Date 2022/1/12 18:23
* @Description 原代理公司成员变为jdk部门
*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler { // AopProxy相当于国家给所有代理公司下发的一个标准
public JdkDynamicAopProxy(ProxyConfig config) {
this.config = config;
}
/**
* 存储需求人员的电话
*/
private ProxyConfig config;
/**
* 生成售货员(代理)
* @return
*/
@Override
public Object getProxy() {
Object target = config.target;
// 使用jdk动态代理技术
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object getProxy(ClassLoader classLoader) {
return null;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 使用通灵术召唤一个调度员,并把打包的工作也交给调度员
ReflectiveMethodInvocation dispatcher = new ReflectiveMethodInvocation(config.target, method, args, config.getInterceptors());
// 需求来了之后按拦截计划去执行
return dispatcher.proceed();
}
}
新增一个使用cglib技术的部门(不懂cglib自己补)
/**
* @Author wmf
* @Date 2022/1/12 18:23
* @Description 新组织的cglib部门
*/
public class CglibAopProxy implements AopProxy, MethodInterceptor { // AopProxy相当于国家给所有代理公司下发的一个标准
public CglibAopProxy(ProxyConfig config) {
this.config = config;
}
/**
* 存储需求人员的电话
*/
private ProxyConfig config;
/**
* 生成售货员(代理)
* @return
*/
@Override
public Object getProxy() {
Object target = config.target;
// 使用cglib代理技术
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallbacks(new Callback[] {this});
return enhancer.create();
}
@Override
public Object getProxy(ClassLoader classLoader) {
return null;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 使用通灵术召唤一个调度员,并把打包的工作也交给调度员
ReflectiveMethodInvocation dispatcher = new ReflectiveMethodInvocation(config.target, method, args, config.getInterceptors());
// 需求来了之后按拦截计划去执行
return dispatcher.proceed();
}
}
两个类都实现了AopProxy(spring的),因为虽然用的技术不一样,但是都是生成代理,统一规范
public interface AopProxy {
/**
* Create a new proxy object.
* Uses the AopProxy's default class loader (if necessary for proxy creation):
* usually, the thread context class loader.
* @return the new proxy object (never {@code null})
* @see Thread#getContextClassLoader()
*/
Object getProxy();
/**
* Create a new proxy object.
*
Uses the given class loader (if necessary for proxy creation).
* {@code null} will simply be passed down and thus lead to the low-level
* proxy facility's default, which is usually different from the default chosen
* by the AopProxy implementation's {@link #getProxy()} method.
* @param classLoader the class loader to create the proxy with
* (or {@code null} for the low-level proxy facility's default)
* @return the new proxy object (never {@code null})
*/
Object getProxy(@Nullable ClassLoader classLoader);
}
我们再模拟一下调度人员
,他的工作是根据配置区分工作该分给哪个部门
/**
* @Author wmf
* @Date 2022/1/19 17:27
* @Description 接待员
*/
public class DefaultAopProxyFactory {
/**
* 根据配置返回不同的部门
* @param config 需求配置
* @return
*/
public AopProxy createAopProxy(ProxyConfig config) {
if (config.isImpl) {
return new JdkDynamicAopProxy(config);
} else {
return new CglibAopProxy(config);
}
}
}
最后模拟代理工厂
,由于代理工厂
对于外界冰淇淋厂家来说也充当一个需求整理人员
,所以继承了ProxyConfig
/**
* @Author wmf
* @Date 2022/1/19 16:50
* @Description 代理公司升级为代理工厂, 代理工厂对于厂家来说也是充当一个需求整理人员,所以继承了ProxyConfig
*/
public class ProxyFactory extends ProxyConfig {
/**
* 接待员
*/
DefaultAopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
/**
* 生成售货员(代理)
* @return
*/
public Object getProxy() {
// 让部门培训售货员
return this.aopProxyFactory.createAopProxy(this).getProxy();
}
}
好了现在再测试一下,先测试一下老机器
public class ChainApplication {
public static void main(String[] args) {
// 厂家的一代冰淇淋机
IceCreamMachine machine = new IceCreamMachine1();
// 厂家定制食品监督计划
MethodInterceptor interceptor1 = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("记录需求至食品监督本:"+invocation.getArguments()[0]);
Object proceed = invocation.proceed();
System.out.println("拍照传给厂家微信:"+proceed);
return proceed;
}
};
// 厂家定制市场调研计划
MethodInterceptor interceptor2 = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("记录需求至市场调研本:"+invocation.getArguments()[0]);
return invocation.proceed();
}
};
// 代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 绑定冰淇淋机
proxyFactory.setTarget(machine);
proxyFactory.setImpl(true);
// 绑定两个拦截计划
proxyFactory.addInterceptor(interceptor1);
proxyFactory.addInterceptor(interceptor2);
// 生成售货员(机器的代理)
IceCreamMachine saler = (IceCreamMachine) proxyFactory.getProxy();
String iceCream = saler.eggCone("原味", "中");
}
}
输出跟原来一模一样:
记录需求至食品监督本:原味
记录需求至市场调研本:原味
开始生产蛋筒冰淇淋
拍照传给厂家微信:原味 蛋筒冰淇淋(中)
再用代码模拟一个新冰淇淋机,2代冰淇淋机没有规范,代码上反应就是没有接口
/**
* @Author wmf
* @Date 2022/1/18 15:37
* @Description 模拟一个2代冰淇淋机,没有接口
*/
public class IceCreamMachine2 {
/**
* 模拟生产杯装冰淇淋
* @param taste 草莓/原味/巧克力
* @param size 大/中/小
* @return 冰淇淋
*/
public String cup(String taste, String size) {
System.out.println("2代:开始生产杯装冰淇淋");
return taste + " 杯装冰淇淋("+size+")";
}
/**
* 模拟生产蛋筒冰淇淋
* @param taste 草莓/原味/巧克力
* @param size 大/中/小
* @return 冰淇淋
*/
public String eggCone(String taste, String size) {
System.out.println("2代:开始生产蛋筒冰淇淋");
return taste + " 蛋筒冰淇淋("+size+")";
}
}
测试一下2代冰淇淋机
/**
* @Author wmf
* @Date 2022/1/18 15:45
* @Description 整个chain的测试类
*/
@SuppressWarnings("ALL")
public class ChainApplication {
public static void main(String[] args) {
// 厂家的冰淇淋机
IceCreamMachine2 machine = new IceCreamMachine2();
// 厂家定制食品监督计划
MethodInterceptor interceptor1 = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("记录需求至食品监督本:"+invocation.getArguments()[0]);
Object proceed = invocation.proceed();
System.out.println("拍照传给厂家微信:"+proceed);
return proceed;
}
};
// 厂家定制市场调研计划
MethodInterceptor interceptor2 = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("记录需求至市场调研本:"+invocation.getArguments()[0]);
return invocation.proceed();
}
};
// 代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 绑定冰淇淋机
proxyFactory.setTarget(machine);
// 没有规范
proxyFactory.setImpl(false);
// 绑定两个拦截计划
proxyFactory.addInterceptor(interceptor1);
proxyFactory.addInterceptor(interceptor2);
// 生成售货员(机器的代理)
IceCreamMachine2 saler = (IceCreamMachine2) proxyFactory.getProxy();
String iceCream = saler.eggCone("原味", "中");
}
}
输出:
记录需求至食品监督本:原味
记录需求至市场调研本:原味
2代:开始生产蛋筒冰淇淋
拍照传给厂家微信:原味 蛋筒冰淇淋(中)
还是符合预期,说明代理工厂
的这次技术改造成功了!!!
对比spring
ProxyFactory 对比 ProxyFactory
DefaultAopProxyFactory 对比 DefaultAopProxyFactory
over~
版权声明:
作者:zhangchen
链接:https://www.techfm.club/p/45612.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论