c. Cglib代理
1)静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是Cglib代理
2) Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展,有些书也将Cglib代理归属到动态代理。
3) Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截。
4)在AOP编程中如何选择代理模式:
1、目标对象需要实现接口,用JDK代理目标
2、对象不需要实现接口,用Cglib代理。
5) Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。
CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
缺点:无法处理final方法
目标类:
/**
* 目标类
*/
public class CglibDao {
public void getMethod(){
System.out.println("需要增强方法的主体内容");
}
}
创建代理类的类
/**
* @author shizi 2022/1/25
* 创建代理类的类
*/
public class CreateCglibProxy implements MethodInterceptor {
/**
* 聚合目标类
*/
private Object object;
public CreateCglibProxy(Object object) {
this.object = object;
}
/**
* 获取代理对象
* @return
*/
public Object getCglibProxy(){
//创建一个cglib对象
Enhancer enhancer = new Enhancer();
//设置代理对象的父类即目标类
enhancer.setSuperclass(object.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建代理类对象并返回
return enhancer.create();
}
/**
* 用于增强目标类的方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理开始-----------");
Object invoke = method.invoke(object, objects);
System.out.println("cglib代理结束-----------");
return invoke;
}
}
测试
public class Test {
public static void main(String[] args) {
//创建目标对象
CglibDao cglib = new CglibDao();
CreateCglibProxy createCglibProxy = new CreateCglibProxy(cglib);
//获取代理对象
CglibDao cglibProxy = (CglibDao)createCglibProxy.getCglibProxy();
cglibProxy.getMethod();
}
}
总结JDK动态代理和CGLIB动态代理:
相同点:都是在内存中去创建代理对象,功能也是一样的,都是完成对目标方法的增强
不同点:
jdk代理:要求目标类必须实现一个接口,内存中创建出来的代理类也会实现相同的接口
cglib代理:目标类不用实现接口,可以只是一个普通的类,在内存中创建出的代理类是
目标类的子类
总结:动态代理实际上都是用于增强目标方法,如果需要增强的类实现了接口,我们需要采用
JDK代理,如果没有实现接口,我们采用Cglib代理!!
动态代理在以后开发中的作用:
SpringAop(面向切面编程:底层就是通过代理模式实现的):
模块1:
模块2:
模块3:
假设某项目有很多模块,每个模块封装了不同业务逻辑,我们以后使用框架进行开发,目的可以提高开发效率,可以让开发人员只去关注核心业务,不去关注一些非核心的业务!!!
提一个需求:希望每个模块都能完成日志的收集,当任意一个模块的代码发生了异常,这个时候希望整理成日志文档,方便开发人员排错!
注意:日志收集的代码不属于核心业务,日志收集的代码是每个模块都需要的
SpringAop可以完成对核心模块的增强:日志收集的代码(就是需要对每个模块增强的部分)
增强步骤:
1、获取每个模块的目标方法<br /> 2、配置springAop的切面=====》切面(指的就是增强的过程)
切面:<br /> spring会去校验核心模块中的核心类是否实现了接口,如果实现了,在底层使用jdk代理来完成<br /> 如果没有实现,用cglib代理来完成!!
核心类实现了接口 invoke{
日志收集的代码1
通过反射机制调用目标方法
日志收集的代码2<br /> }<br /> 所以说,通过这种方式,可以让非核心代码脱离核心模块,而且方便维护,易于管理!!!
d.工厂模式
简单工厂模式:https://blog.csdn.net/ShuSheng0007/article/details/86634864
核心就是通过一个工厂方法根据不同的条件生产同一类型的产品
抽象工厂模式:https://blog.csdn.net/ShuSheng0007/article/details/86644481
核心在于一个工厂方法生产一个品牌家族的系列产品
工厂方法模式:https://blog.csdn.net/ShuSheng0007/article/details/86636494
核心仍旧是如何创建同一类型产品(都实现同一个接口)的问题,只不过是通过为每一种要生产的产品配备一个工厂,就是说每个工厂只生产一种特定的产品。
简单工厂中创建产品使用反射:
简单工厂类:
public interface Factory {
/**
* 制作手机的方法
*/
Phone makePhone(String className);
}
工厂类:
/**
* 生产手机:通过简单工厂模式来写这个类
*/
public class PhoneFactory implements Factory {
/**
* 生产手机的
* @param className
* @return
*/
@Override
public Phone makePhone(String className) {
if (className != null){
try {
//获取字节码对象
Class aClass = Class.forName(className);
//通过发射机制来创建手机手机实例
Object obj = aClass.newInstance();
if (obj instanceof Phone){
return (Phone) obj;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
return null;
}
}
使用工厂生产产品:
/**
*
* 需求:通过工厂获取手机实例
*/
public class FactoryTest {
public static void main(String[] args) {
//创建工厂实例
Factory factory = new PhoneFactory();
//获取华为实例
Phone phone = factory.makePhone("com.jy.factory.phone.HuaWei");
phone.make();
//获取苹果实例
Phone phone2 = factory.makePhone("com.jy.factory.phone.Iphone");
phone2.make();
}
}