Loading

动态代理的一些理解

关于java的动态代理,有jdk动态代理和cglib动态代理。jdk动态代理是基于接口实现的,而CGlib动态代理是基于继承思想实现的,它能用于没有接口的目标对象的代理,这是jdk动态代理所不具备的功能。如果目标对象有接口实现,选择JDK代理,如果没有接口实现选择Cglib代理

JDK动态代理

具体流程:
1.拿到被代理对象的引用,然后获取他的接口
2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
3.把被代理对象的引用拿到了
4.重新动态生成一个class字节码
5.然后编译

代码很简单了,就是实现
java.lang.reflect.InvocationHandler接口,并使用
java.lang.reflect.Proxy.newProxyInstance()方法生成代理对象

关于jdk动态代理有下面一些总结:

Class getProxyClass(ClassLoader loader, Class... interfaces)

调用getProxyClass()会动态生成Proxy类的子类,并使用loader参数指定的类加载器加载;第二个参数interfaces指定该子类将要继承的接口,可以指定多个接口。

Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

1、ClassLoader loader:目标对象通过getClass方法获取类的所有信息后,调用getClassLoader()
方法来获取类加载器。获取类加载器后,可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要!
2、Class[] interfaces:获取被代理类的所有接口信息,以便于生成的代理类可以具有代理类接口中的所有方法。注意这里表示该类可能是任意类 如果只是java类型 则可以用T表示
3、InvocationHandler h:我们使用动态代理是为了更好的扩展,比如在方法之前做什么,之后做什么等操作。这个时候这些公共的操作可以统一交给代理类去做。这个时候需要调用实现了InvocationHandler 类的一个实现方法。由于自身便实现了这个方法,所以将本类传递过去。
我们首先了一个简单地动态代理类,各部分的功能说明如下:

package com.xxxx.proxy;

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

/**
 * jdk动态代理类
 */
public class JdkHandler implements InvocationHandler {
    //目标对象
    private Object target;
    //目标对象通过带参构造器传递进来


  public JdkHandler(Object target){
      this.target = target;

  }

    /**
     *
     * getProxy用来获取代理对象
     * 获取代理对象
     * @return
     *
     * 获取代理对象
     * public static Object newProxyInstance(ClassLoader loader,Class[] interface,InvocationHandler h)
     * 三个参数的说明
     * loader:类加载器
     * interface:接口数组
     * InvocationHandler接口(传入InvocationHandler接口的实现类,一般本类就会实现InvocationHandler接口,这里是JdkHandler实现了这个接口)
     */
    public Object getproxy(){
    Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    return  obj;
}


    /**
     * 1 调用目标对象的方法
     * 2 增强目标对象的行为
     * @param proxy  调用该方法的代理实例(这里没有用到它)
     * @param method 目标对象的方法
     * @param args 目标对象的方法所需的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = method.invoke(target,args);

        return object;
    }
}

有两个接口
Marry接口中的方法

package com.xxxx.proxy;

public interface Marry {
    void toMarry();
}

Study中的接口方法

package com.xxxx.proxy;

public interface Study {
    void university();
}

假如类You实现了Marry和Study接口

package com.xxxx.proxy;

public class You implements Marry, Study{
    @Override
    public void toMarry() {
        System.out.println("我要结婚了...");
    }

    @Override
    public void university() {
        System.out.println("study in xidian...");
    }
}

我们要对这两个接口中的方法进行代理,代理程序的书写如下:

package com.xxxx.proxy;

public class JdkHandlerTest {
    public static void main(String[] args) {
        //目标对象
      You you = new You();

      //得到代理类,用jdkHandler表示
       JdkHandler jdkHandler = new JdkHandler(you);
       //得到代理对象 用marry表示这里  左边是目标对象所实现的接口 右边是通过代理类获取的代理对象
     Marry marry =(Marry)  jdkHandler.getproxy();
        //通过代理对象调用目标对象的方法
     marry.toMarry();

        System.out.println("--------");

        Study study = (Study) jdkHandler.getproxy();
        study.university();

    }
}

CGlib动态代理

CGlib的思路是通过目标类生成代理类的父类,需要实现MethodInceptor接口

package com.xxxx.CGlib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibInterceptor implements MethodInterceptor {
    /**
     * 拦截器
     * 1 目标对象的方法调用
     * 2 行为增强
     * @param o  cglib动态生成的代理类的实例
     * @param method  实体类所调用的都被代理的方法的引用
     * @param objects  参数列表
     * @param methodProxy  生成的代理类对方法的代理引用
     * @return
     * @throws Throwable
     */

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        //调用目标类的方法
        Object obj = methodProxy.invoke(target,objects);
        return obj;
    }

    /**
     * 目标对象
     */

    private Object target;

    /**
     * 通过构造器传入目标对象
     * @param target
     */
    public CglibInterceptor(Object target){
        this.target = target;

    }

    /**
     * 获取代理类
     *
     */
public Object getProxy(){
    //通过Enhancer对象中的create方法生成一个类,用于生成代理对象
    Enhancer enhancer = new Enhancer();

    //设置父类,将目标类作为代理类的父类
    enhancer.setSuperclass(target.getClass());

    //实现一个callback的子接口,括号里面放置的是拦截器,这里的拦截器是CglibInterceptor  也就是回调对象为本身对象
    enhancer.setCallback(this);

    //生成代理类对象并返回给调用者
    return enhancer.create();

}


}

加入需要代理User类中的test方法

package com.xxxx.CGlib;

public class User {
    public void test(){
        System.out.println("cglib动态代理");
    }
}

测试代码如下

package com.xxxx.CGlib;

import com.xxxx.proxy.Marry;
import com.xxxx.proxy.You;

public class CglibProxyTest {

    public static void main(String[] args) {
        You you = new You();
        CglibInterceptor cglibInterceptor = new CglibInterceptor(you);
       Marry marry=(Marry) cglibInterceptor.getProxy();

       marry.toMarry();

       User user = new User();
       CglibInterceptor cglibInterceptor1 = new CglibInterceptor(user);
     User user1 = (User) cglibInterceptor1.getProxy();
     user1.test();

    }
}

AOP

Spring的两大特性中的AOP就是基于动态代理实现的,AOP的注意点在于定义切面。
比如定义前置通知:
@Before("execution( chapter04.concert.Performance.perform(..))")*
其中execution(* chapter04.concert.Performance.perform(..))被称为AspectJ切点表达式,每一部分的讲解如下:

@Before:该注解用来定义前置通知,通知方法会在目标方法调用之前执行
execution:在方法执行时触发
*:表明我们不关心方法返回值的类型,即可以是任意类型
chapter04.concert.Performance.perform:使用全限定类名和方法名指定要添加前置通知的方法
(..):方法的参数列表使用(..),表明我们不关心方法的入参是什么,即可以是任意类型
posted @ 2021-12-30 17:52  kevin_kay  阅读(46)  评论(0编辑  收藏  举报