欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring中的常见设计模式

程序员文章站 2022-04-15 17:49:21
代理模式代理模式常用的地方: 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