spring中的常见设计模式
程序员文章站
2022-07-10 19:10:14
代理模式代理模式常用的地方: AOP的功能完全继承到了Spring事务管理、日志和其他各种特性的上下文中。 Authentication权限认证 Logging日志 Transctions Manager事务 Lazy Loading懒加载 Context Process上下文处理 Error Handler错误跟踪(异常捕获机制) Cache缓存处理分为静态代理、动态代理 JDK 动态代理: CGLib 动态代理: cglib.jar (全称 Co...
代理模式
-
代理模式常用的地方:
AOP的功能完全继承到了Spring事务管理、日志和其他各种特性的上下文中。 Authentication权限认证 Logging日志 Transctions Manager事务 Lazy Loading懒加载 Context Process上下文处理 Error Handler错误跟踪(异常捕获机制) Cache缓存处理
-
分为静态代理、动态代理
JDK 动态代理: CGLib 动态代理: cglib.jar (全称 Code Generation Library 代码生成库) asm.jar(全称 assembly,装配)
-
代理的特点:
1、执行者、被代理人 2、对于被代理人来说,这件事情是一定要做的,但是我自己又不想做或者没有时间做,找代理。 3、需要获取到被代理的人个人资料。
-
穷举法:
租房中介:中介和你 火车票黄牛:黄牛和你 媒人:媒婆和你 明星经纪人:经纪人和明星 刘德华要开演唱会(长沙)、准备工作和善后工作 快递:
-
总结:做了一件什么事情呢?
字节码重组
可以做一件什么事情?
可以在每一个方法调用之前加一些代码,在方法调用之后再加一些代码
AOP:事务代理(声明式事务,哪个方法需要加事务,哪个方法不需要加事务)
-
日志监听
service 方法 开启一个事务(open) 事务的执行(是由我们自己的代码完成的) 监听到是否有异常,可能需要根据异常的类型来决定这个事务是否要回滚还是继续提交 (commit/rollback) 事务要关闭(close)
-
代理的原理
1、拿到被代理对象的引用,然后获取它的接口; 2、JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口。 3、把被代理对象的引用也拿到了 4、重新动态生成一个class字节码 5、然后编译
-
JDK代理与cglib代理
JDK代理:实现自InvocationHandler接口,实现代理 cglib代理:实现自MyMethodInterceptor接口,实现代理 JDK的动态动力是通过接口来进行强制转换的 生成以后的代理对象,可以强制转换为接口 CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法, 生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类), 子类引用赋值给父类。 cglib new出来以后的对象,是被代理对象的子类(继承课我们自己写的那个类), OOP,在new子类之前,实际上默认先调用了我们super()方法的, new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用。 子类重写了父类的所有的方法, 我们改变子类对象的某些属性,是可以间接的操作父类的属性的。
-
Cglib和jdk动态代理的区别?
1、Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 2、Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理。
-
什么时候用cglib什么时候用jdk动态代理?
1、目标对象生成了接口 默认用JDK动态代理 2、如果目标对象使用了接口,可以强制使用cglib 3、如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换
-
JDK动态代理和cglib字节码生成的区别?
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类 2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的
-
Spring如何选择是用JDK还是cglib?
1、当bean实现接口时,会用JDK代理模式 2、当bean没有实现接口,用cglib实现 3、可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)
-
cglib举例:
1、引入依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2、创建一个被代理人的对象:
public class ZhangSanFindLove {
public void findLove(){
System.out.println("牛郎织女七夕来相会...");
}
}
3、创建一个代理人对象:
public class MyMethodInterceptor implements MethodInterceptor {
/**
* @param clazz 文件的字节码文件
* @return 具体的对象
*/
public Object getInstance(Class clazz){
//通过Enhancer对象进行代理操作
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(clazz);
//设置回调
enhancer.setCallback(this);
//调用Enhancer对象的创建并返回
return enhancer.create();
}
/**
* @param className 文件的全路径名称
* @return 具体的对象
*/
public Object getInstance(String className){
//通过Enhancer对象进行代理操作
Enhancer enhancer = new Enhancer();
//设置父类
try {
enhancer.setSuperclass(Class.forName(className));
} catch (ClassNotFoundException e) {
}
//设置回调
enhancer.setCallback(this);
//调用Enhancer对象的创建并返回
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
System.out.println("我是媒婆,你得给我找个异性");
System.out.println("--------------------------");
/**
* 不能使用invoke,invoke是指向自己
* Cglib是给指定的类添加一个子类对象,所以应该指向父类节点
* 为父类自动塑造出一个子类
*/
proxy.invokeSuper(o , objects);
System.out.println("--------------------------");
System.out.println("合适,就步入婚礼的殿堂");
return null;
}
}
-
测试类:
public class FindLoveTest { public static void main(String[] args) { ZhangSanFindLove instance = (ZhangSanFindLove)new MyMethodInterceptor().getInstance("gupaoedu.vip.agent.cglib.ZhangSanFindLove"); ZhangSanFindLove instance1 = (ZhangSanFindLove)new MyMethodInterceptor().getInstance(ZhangSanFindLove.class); instance.findLove(); instance1.findLove(); } }
本文地址:https://blog.csdn.net/weixin_42779560/article/details/108254660
上一篇: 字符串变为函数