动态代理以及动态代理如何实现AOP

                                                    动态代理以及动态代理如何实现AOP

一、代理设计模式

         什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被代理的人能干活呀。

        举例:晚会的主办方要举行歌舞表演,要找歌手唱歌和跳舞 ,主办方会找歌手的经纪人来确认沟通直至签合同,这样在晚会时歌手就会在舞台上唱歌和跳舞。实际上经纪人就是歌手的代理人

1)唱歌跳舞接口      

public interface SingerService {

    public void sing(String songName);

    public void dance(String danceName);
}
2)某个歌手来进行唱歌跳舞

public class SingerServiceImpl implements SingerService {

    public void sing(String songName) {
        System.out.println("唱歌曲名为" + songName+"的歌曲");
    }

    public void dance(String danceName){
        System.out.println("跳舞蹈名为" + danceName+"的舞蹈");
    }
}
3)歌手的经纪人通过让歌手唱歌和跳舞来实现唱歌跳舞接口

public class SingerProxy implements SingerService {

    private SingerService singerService;

    public SingerProxy(SingerService singerService){
        this.singerService = singerService;
    }

    public void sing(String songName){
        System.out.println("将要执行方法名为sing的方法");
        singerService.sing(songName);
        System.out.println("已经执行完方法名为sing的方法");
    }

    public void dance(String danceName){
        System.out.println("将要执行方法名为dance的方法");
        singerService.dance(danceName);
        System.out.println("已经执行完方法名为dance的方法");
    }
}
4)晚会主办方邀请歌手进行歌舞表演

public class TestProxy {

    public static void main(String args[]){
        SingerService singerService = new SingerServiceImpl();
        SingerProxy proxy = new SingerProxy(singerService);

        proxy.sing("日不落");
        System.out.println("");
        proxy.dance("霓裳羽衣舞");
    }
}

运行结果:


    代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口。

    由于我们现在不希望静态地有SingerProxy类存在,希望在代码中,动态生成器二进制代码,加载进来,所以才有了动态代理

二、动态代理

    动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组);然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,初始化之后将对象返回给调用的客户端。这样客户端拿到的就是一个实现你所有的接口的Proxy对象

   动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可.

public class MyInvocationHandler implements InvocationHandler {
    private Object service;

    public MyInvocationHandler(Object service) {
        this.service = service;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("将要执行方法名为" + method.getName() + "的方法");
        Object result = method.invoke(service, args);
        System.out.println("已经执行完方法名为" + method.getName() + "的方法");
        System.out.println(method.getName()+"方法的返回值result="+result);
        System.out.println("");
        return result;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                service.getClass().getInterfaces(), this);
    }
}

public class TestDynamicProxy {

    public static void main(String args[]){
        SingerService singerService = new SingerServiceImpl();
        MyInvocationHandler myInvocationHandler =  new MyInvocationHandler(singerService);
        SingerService proxy = (SingerService)myInvocationHandler.getProxy();

        proxy.sing("日不落");
        proxy.dance("霓裳羽衣舞");

    }
}
     运行结果:

     

    1.Proxy类的newInstance()方法

        该方法有有三个参数:
    i)ClassLoader loader:它是类加载器类型,用来加载动态生成的Proxy类
    ii)Class[] interfaces:指定newProxyInstance()方法返回的对象要实现哪些接口,没错,可以指定多个接口,例如上面例子只我们只指定了一个接口,即SingerServiceImpl类所实现的接口也就是SingerService这个接口
    iii)InvocationHandler h:它是最重要的一个参数!它是一个接口!它的名字叫调用处理器!你想一想,上面例子中proxy对象是SingerService接口的实现类对象,那么它一定是可以调用sing(String songName)和dance(String danceName)方法了,其实无论你调用代理对象的什么方法,它都是在调用MyInvocationHandler的invoke()方法

    2 .Invocation Handler管理器

      为了构造出具有通用性和简单性的代理类,可以将所有的触发真实角色动作交给一个触发的管理器,让这个管理器统一地管理触发。这种管理器就是Invocation Handler。

      InvocationHandler接口只有一个方法,即invoke()方法!它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。

  InvocationHandler的invoke()方法的参数有三个:
      i)Object proxy:代理对象,也就是Proxy.newProxyInstance()方法返回的对象,通常我们用不上它;
      ii)Method method:表示当前被调用方法的反射对象,例如 proxy.sing("日不落");,那么method就是sing(String songName)方法的反射对象;
   iii)Object[] args:表示当前被调用方法的参数,如proxy.sing("日不落");参数是"日不落"
 最后要说的是invoke()方法的返回值为Object类型,它表示当前被调用的方法的返回值,当然proxy.sing("日不落");方法是没有返回值的,所以invoke()返回的就必须是null了。

  三、java动态代理实现AOP

     1.什么是AOP

        AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

      AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

     使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

  2.动态代理实现AOP

import java.lang.reflect.Method;

public interface AOPMethod {

    //执行前切入
    public void before(Object proxy, Method method, Object[] args);

    //执行后切入
    public void after(Object proxy, Method method, Object[] args);
}


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyAOPInvocationHandler implements InvocationHandler {
    private Object service;
    private AOPMethod aopMethod;

    public MyAOPInvocationHandler(Object service,AOPMethod aopMethod) {
        this.service = service;
        this.aopMethod = aopMethod;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.aopMethod.before(proxy, method,args);//执行前切入
        Object result = method.invoke(service, args);
        this.aopMethod.after(proxy, method,args);//执行后切入
        System.out.println("");
        return result;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                service.getClass().getInterfaces(), this);
    }
}
import java.lang.reflect.Method;

public class TestAOPDynamicProxy {
    public static void main(String args[]){
        SingerService singerService = new SingerServiceImpl();
        MyAOPInvocationHandler myAOPInvocationHandler =  new MyAOPInvocationHandler(singerService, new AOPMethod() {
            public void before(Object proxy, Method method, Object[] args) {
                System.out.println("将要执行方法名为" + method.getName() + "的方法");
            }

            public void after(Object proxy, Method method, Object[] args) {
                System.out.println("已经执行完方法名为" + method.getName() + "的方法");
            }
        });
        SingerService proxy = (SingerService)myAOPInvocationHandler.getProxy();

        proxy.sing("日不落");
        proxy.dance("霓裳羽衣舞");

    }
}
   运行结果:

   


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AOP实现中,可以通过静态代理和动态代理两种方式来实现代理功能。静态代理是在编译时就已经创建好代理对象的代理方式,而动态代理则是在运行时通过反射机制动态生成代理对象的方式。静态代理需要编写代理类,而动态代理则可以通过框架自动生成代理对象。 在AOP实现中,基于接口的动态代理通常使用JDK动态代理实现。JDK动态代理是通过Java的反射机制,在运行时动态生成代理类,实现对目标对象方法的拦截和增强。它要求目标对象必须实现一个接口,代理对象则实现了这个接口,并在调用目标对象的方法前后插入特定的逻辑。 基于类的动态代理通常使用cglib来实现。Cglib是一个强大的字节码生成库,通过动态生成目标类的子类来实现代理。与JDK动态代理不同,基于类的动态代理不需要目标类实现任何接口,因此更加灵活。 总结起来,AOP实现中的静态代理和动态代理分别采用了不同的技术来实现代理功能。静态代理是在编译时创建代理对象,而动态代理是在运行时通过反射或字节码生成技术动态生成代理对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Spring AOP基础之代理模式.静态代理和动态代理](https://blog.csdn.net/zhangchen124/article/details/127111423)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [AOP从静态代理到动态代理(Emit实现)详解](https://download.csdn.net/download/weixin_38698433/14914135)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值