AOP的实现,JDK动态代理和CGLIB动态代理

一、jdk动态代理实现

1.接口

代码如下(示例):

package com.bjtu;

public interface StudentDao {
    public int add(int a, int b);

    public String update(String id);
}

2.接口实现类

代码如下(示例):

package com.bjtu;

public class StudentDaoImpl implements StudentDao {

    @Override
    public int add(int a, int b) {
        System.out.println("执行方法------------");
        return a+b;
    }

    @Override
    public String update(String id) {
       return id;
    }
}

3.代理类

代码如下(示例):

package com.bjtu;

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

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {StudentDao.class};
      /*可用匿名内部类
      Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });*/
        StudentDaoImpl stu = new StudentDaoImpl();
        StudentDao stuDao = (StudentDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new StudentProxy(stu));
        int result = stuDao.add(1,2);
        System.out.println("result: " + result);

    }

    static class StudentProxy implements InvocationHandler {
        public Object obj;
        public StudentProxy(Object obj){
            this.obj = obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("方法之前执行:" + method.getName()+"传递的参数"+ Arrays.toString(args));
            Object res = method.invoke(obj,args);
            System.out.println("方法之后执行-------" + res);
            return res;
        }
    }
}

执行结果如下:
在这里插入图片描述

二、CGILIB动态代理实现

1.业务类

代码如下(示例):

package com.bjtu;

public class Service {
    public Service() {
        System.out.println("=======构造方法========");
    }

    //final修饰,无法增强
    final public void finalMethod() {
        System.out.println("=========finalMethod========");
    }

    public String testMethod(String name) {
        System.out.println("========testMethod==========");
        return  "name = " + name;
    }
}

拦截器

package com.bjtu;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public String intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("========插入前置通知=======");
        //通过代理类调用父类中的方法
        String name = (String) methodProxy.invokeSuper(o, objects);
        System.out.println("========后置通知======");
        return name;
    }
}

测试类

package com.bjtu;

import org.springframework.cglib.proxy.Enhancer;

public class Client {
    public static void main(String[] args) {


        //通过cglib动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        //设置enhancer对象的父类
        enhancer.setSuperclass(Service.class);

        //设置enhancer的回调对象,拦截处理器
        enhancer.setCallback(new MyMethodInterceptor());

        //创建代理对象
        Service proxy = (Service) enhancer.create();

        //通过代理对象调用方法
       String obj = proxy.testMethod("张三");
        System.out.println(obj);
    }
}

执行结果如下:
在这里插入图片描述

三、两者区别

Jdk动态代理:
必须有接口。创建接口实现类的代理对象,通过代理对象来增强其中的方法。
使用Proxy类,调用newProxyInstance方法,三个参数:类加载器,接口,实例(InvocationHandler的实现类)

为什么jdk动态代理必须要有接口?

因为动态代理底层是生成字节码文件,通过修改字节码文件,从而达到动态代理的效果。字节码文件是二进制的我们看不懂,需要反编译。
问题来了,Java底层生成的$Proxy长这样。
在这里插入图片描述
jdk动态代理帮我们增强方法,生成代理类对象,字节码中的代理类 $Proxy 默认是继承接口Proxy的,而java是单继承的,所以必须有接口。

cglib是通过生成被代理对象的子类的方式,增强方法的,也就是拿到被代理对象的一个模板,对其进行增强。也就不需要接口了。

四、AOP使用的是哪种动态代理方式?

AOP在选择动态代理方式的逻辑如图中所示:
在这里插入图片描述

源码判断时候,if( || ||)三个条件。第一个判断isOptimize,默认为假;第二个判断proxyTargetClass,默认为假;第三个判断,是否为接口。
因此,当被增强类继承接口时,都是用jdk动态代理。
当被增强类不继承接口时,需要判断proxyTargetClass,不指定的话,默认为false。
指定为true才会走CGLIB动态代理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值