• Spring的AOP (代理模式)


    代理模式

            在Java开发中是一种比较常见的设计模式。设计目的旨在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。如房东出租房子   

     客户(客户类)          中介(代理类)      房东(委托类)一样。

    什么是代理模式?
            为某一个对象(委托类)提供一个代理(代理类),用来控制对这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤,将请求分配给指定对象。

    代理模式二个设计原则

    1,代理类与委托类有相似的行为(共同方法)

    2,代理类增强委托类的行为

    目录

    静态代理

    什么是静态代理?

    代理三要素

    静态代理特点

    静态代理实现(模拟出租房子)

    创建共同父类接口

    创建房东

    创建代理(通过构造器传递行参(目标))

    测试租房

    动态代理

    动态代理特点

    Jdk动态代理

    newProxyInstance方法

    创建接口父类 (如果目标对象没有接口实现,则不能通过JDK动态代理生成代理对象)

    创建房东(目标类)

    创建代理类

    测试类

    CGLIB代理

    CGLIB代理实现


    静态代理

    什么是静态代理?

            某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。

    代理三要素

    1. 有共同的行为(接口)
    2. 目标角色(实现行为)
    3. 代理角色(实现目标行为,帮助目标角色增加行为)

    静态代理特点

    1. 目标角色固定
    2. 在应用程序执行前就得到目标角色
    3. 代理对象会增强目标对象的行为
    4. 有可能存在多个代理引起类爆炸”(缺点:一个工作需要一个代理,多个代理引起类爆炸)

    静态代理实现(模拟出租房子)

    创建共同父类接口

    1. package com.lsf.statics;
    2. /**
    3. * 静态代理
    4. * 父类或者父接口
    5. * 共同行为
    6. */
    7. public interface RentHouse {
    8. // 共同行为 租房
    9. public void ToRentHouse();
    10. }

    创建房东

    1. package com.lsf.statics;
    2. //模拟户东租房
    3. public class Tenement implements RentHouse{
    4. public void ToRentHouse() {
    5. System.out.println("我想要出租一个豪宅,面朝大海春暖花开");
    6. }
    7. }

    创建代理(通过构造器传递行参(目标))

    1. package com.lsf.statics;
    2. /**
    3. * 静态代理
    4. * 代理对象
    5. * 1,实现目标行为(租房)
    6. * 2,增强目标行为
    7. */
    8. public class AgencyProxy implements RentHouse {
    9. //目标对象
    10. private RentHouse target;
    11. //通过构造器传递行参(目标)
    12. public AgencyProxy(RentHouse target){
    13. this.target=target;
    14. }
    15. public void ToRentHouse() {
    16. //增强目标行为
    17. System.out.println("出租房子了!!! 便宜方便 快来啊");
    18. //实现目标行为(租房)
    19. target.ToRentHouse();
    20. //增强目标行为
    21. System.out.println("出租成功,来签合同啊,亲");
    22. }
    23. }

    测试租房

    1. package com.lsf;
    2. import com.lsf.statics.AgencyProxy;
    3. import com.lsf.statics.RentHouse;
    4. import com.lsf.statics.Tenement;
    5. public class Starter {
    6. public static void main(String[] args) {
    7. //目标对象
    8. RentHouse target = new Tenement();
    9. AgencyProxy proxy = new AgencyProxy(target);
    10. proxy.ToRentHouse();
    11. }
    12. }

     

    动态代理

    动态代理:

    (注:JDK动态代理的目标对象必须有接口实现)

            在创建代理对象上更加的灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类。

    优点:

            代理的行为可以代理多个方法,即满足生产需要的同时又达到代码通用的目的。

    实现方式:

            jdk动态代理

            CGLIB代理 

    动态代理特点

    1. 目标对象不固定
    2. 在应用程序执行时动态创建目标对象
    3. 代理对象会增强目标对象的行为

    Jdk动态代理

    newProxyInstance方法

    Proxy类:
            Proxy类是专门完成代理的操作可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下操作方法:

    1. public static 0bject newProxyInstance(
    2. ClassLoader loader,
    3. class[ ] interfaces,
    4. InvocationHandler h){
    5. }

    创建接口父类 (如果目标对象没有接口实现,则不能通过JDK动态代理生成代理对象)

    1. package com.lsf.statics;
    2. /**
    3. * 静态代理
    4. * 父类或者父接口
    5. * 共同行为
    6. */
    7. public interface RentHouse {
    8. // 共同行为 租房
    9. public void ToRentHouse();
    10. }

    创建房东(目标类)

    1. package com.lsf.statics;
    2. /**
    3. * 静态代理
    4. * 父类或者父接口
    5. * 共同行为
    6. */
    7. public interface RentHouse {
    8. //租房
    9. public void ToRentHouse();
    10. }

    创建代理类

    1. package com.lsf.dynamic;
    2. import java.lang.reflect.AnnotatedType;
    3. import java.lang.reflect.InvocationHandler;
    4. import java.lang.reflect.Method;
    5. import java.lang.reflect.Proxy;
    6. /**
    7. * Jdk动态代理
    8. */
    9. public class Jdkproxy {
    10. //目标对象(目标不确定所有使用 Object )
    11. private Object target;
    12. //构造器传递参数
    13. public Jdkproxy (Object target){
    14. this.target=target;
    15. }
    16. /**
    17. * 得到代理对象
    18. * @return
    19. */
    20. public Object getProxy(){
    21. /**
    22. * 通过调用Proxy 代理类中的静态方法newProxyInstance(),得到代理对象
    23. */
    24. //定义生成代理对象进行加载
    25. ClassLoader loader = this.getClass().getClassLoader();
    26. //定义代理对象通过的接口
    27. Class[] interfase = target.getClass().getInterfaces();
    28. InvocationHandler invocationHandler = new InvocationHandler() {
    29. /**
    30. * 当代理对象调用方法时,invoke方法就会被执行一次
    31. *
    32. */
    33. @Override
    34. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    35. System.out.println("方法执行前,可以操作");
    36. //调用目标对象方法
    37. //通过反射中invoke方法,调用目标对象的指定方法
    38. /**
    39. * 反射中的 invoke() 方法
    40. * target 对象
    41. * args 方法需要参数
    42. */
    43. method.invoke(target,args);
    44. System.out.println("方法执行后,可以操作");
    45. //return 方法的返回值
    46. return null;
    47. }
    48. };
    49. //调用方法,获取代理对象
    50. Object object = Proxy.newProxyInstance(loader,interfase,invocationHandler);
    51. return object;
    52. }
    53. }

    测试类

    1. package com.lsf;
    2. import com.lsf.dynamic.Jdkproxy;
    3. import com.lsf.statics.RentHouse;
    4. import com.lsf.statics.Tenement;
    5. public class Starter {
    6. public static void main(String[] args) {
    7. //目标对象
    8. RentHouse target = new Tenement();
    9. //得到代理
    10. Jdkproxy jdkproxy = new Jdkproxy(target);
    11. //获取代理对象
    12. RentHouse object = (RentHouse) jdkproxy.getProxy();
    13. //通过代理调用方法
    14. object.ToRentHouse();
    15. }
    16. }

     

    CGLIB代理

    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能使用JDK的动态代理,cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,

    特点:

    采用的是继承所以不能对final修饰的类进行代理。
     

    CGLIB代理实现

    1,添加pom.xml依赖

    1. org.lucee
    2. cglib
    3. 2.2.2

    2,定义代理类

    1. package com.lsf.dynamic;
    2. import org.springframework.cglib.proxy.Enhancer;
    3. import org.springframework.cglib.proxy.MethodInterceptor;
    4. import org.springframework.cglib.proxy.MethodProxy;
    5. import java.lang.reflect.Method;
    6. /**Cgilb动态代理
    7. * 继承思想
    8. * 创建一个代理类,代理类是目标类的子类,代理类对目标类进行重写
    9. */
    10. public class CgilbProxy {
    11. //得到代理对象
    12. private Object target;
    13. public CgilbProxy(Object target){
    14. this.target=target;
    15. }
    16. public Object getProxy(){
    17. //通过Enhancer对象的create()方法生成一个类,生成代理类
    18. Enhancer enhancer = new Enhancer();
    19. //设置当前类的父类(将目标类作为父类)
    20. enhancer.setSuperclass(target.getClass());
    21. //定义方法拦截器
    22. MethodInterceptor methodInterceptor = new MethodInterceptor() {
    23. /**
    24. * 当对象调用方法时,intercept就会调用
    25. * @param o Cglib动态代理生成代理类
    26. * @param method 目标方法
    27. * @param objects 方法需要参数
    28. * @param methodProxy 代理对象方法引用
    29. * @return
    30. * @throws Throwable
    31. */
    32. @Override
    33. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    34. System.out.println("方法执行前...");
    35. Object result = method.invoke(target,objects);
    36. System.out.println("方法执行后...");
    37. return null;
    38. }
    39. };
    40. //设置代理过程(调用目标对象方法,增强目标行为)
    41. enhancer.setCallback(methodInterceptor);
    42. //生成一个类
    43. return enhancer.create();
    44. }
    45. }

    3,测试

    1. package com.lsf;
    2. import com.lsf.dynamic.CgilbProxy;
    3. import com.lsf.dynamic.Jdkproxy;
    4. import com.lsf.statics.RentHouse;
    5. import com.lsf.statics.Tenement;
    6. public class CglibTest {
    7. public static void main(String[] args) {
    8. //目标对象
    9. RentHouse target = new Tenement();
    10. //得到代理
    11. CgilbProxy cgilbProxy = new CgilbProxy(target);
    12. //获取代理对象
    13. RentHouse object = (RentHouse) cgilbProxy.getProxy();
    14. //通过代理调用方法
    15. object.ToRentHouse();
    16. }
    17. }

     

  • 相关阅读:
    Leetcode 292. Nim Game
    torch.cat函数用法
    AT24C02存储与读取数据
    两种MySQL OCP认证应该如何选?
    C语言中的类型转换
    git命令的操作
    操作系统银行家算法
    HTML && CSS
    k8s集群安装v1.20.9后-2-改造部署自己的服务k8sApp,增加istio
    liunx 基础命令应用
  • 原文地址:https://blog.csdn.net/weixin_47514459/article/details/126877742