Aop编程之动态代理

1、Java代理介绍

Java中的代理方式包括静态代理和动态代理。 静态代理在编译期间就确定了代理对象,动态代理是在运行期间动态生成代理对象。动态代理包括cglib动态代理和jdk动态代理,在目标对象有接口的情况下,可以使用jdk动态代理或者cglib动态代理;如果目标对象没有接口,则无法使用jdk动态代理,只能使用cglib动态代理。下面是介绍分别实现cglib动态代理和jdk动态代理的简单例子。

2、cglib动态代理

下面的例子中, 要增强User类的talk()方法,在方法开始和结束时都输出当前的系统时间,但是不希望修改User类的代码,又因为User类没有实现接口,在这种情况下可以使用cglib动态代理实现。

代码逻辑:

  1. 创建User类,并且编写talk()方法;
  2. 创建User类的代理增强类,用于增强talk()方法的代码逻辑;
  3. 编写测试类,先创建一个User对象,然后通过增强类根据这个对象创建一个增强对象,最后执行增强对象的talk方法。

  • User类
public class User {
    public void talk(){
        System.out.println("【交谈中。。。】");
    }
}

  • User代理增强类
  1. 执行Enhancer.create()方法,传入对应的参数,拿到一个增强后的对象;
  2. 重写MethodInterceptor()接口的 intercept()方法 编写具体的增强代码逻辑。
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class UserExtendByCglib {
    public static Object getProxy(Object target){
        /**
         * Enhancer.create()方法, 参数1是对象的字节码, 参数2是拦截方法的程序的对象, 返回值是一个增强后的对象
         */
        return Enhancer.create(target.getClass(), new MethodInterceptor() {
            /**
             * @param proxy  增强后的代理对象
             * @param method  需要代理增强的方法
             * @param args     需要代理增强的方法的参数
             * @param methodProxy  增强后的代理对象的方法
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //增强代码逻辑1:开始时间
                System.out.println(System.currentTimeMillis());
                //执行最初的方法
                Object result = method.invoke(target, args);
                //增强代码逻辑2:结束时间
                System.out.println(System.currentTimeMillis());
                return result;
            }
        });
    }
}

  • 测试代码
public class TestUser {
    public static void main(String[] args) {
        // 创建未被增强的对象
        User user = new User();
        // 通过代理对象, 对初始对象增强, 然后得到一个增强对象
        User userProxy = (User) UserExtendByCglib.getProxy(user);
        // 执行增强后的方法
        userProxy.talk();

    }
}

3、jdk动态代理

在下面的例子中,想要对Student类的talk方法增强,talk是Student实现Talk接口重写后的方法,这种情况可以使用jdk动态代理实现。

代码逻辑:

  1. 定义一个Talk接口,其中包含talk()方法;
  2. 创建Student类,实现Talk接口,重写talk()方法;
  3. 创建Talk接口的代理增强类,用于增强talk()方法的代码逻辑;
  4. 编写测试类,先创建一个Student对象,然后通过增强类根据这个对象创建一个增强对象,最后执行增强对象的talk()方法。
  • 创建talk接口
public interface Talk {
    void talk();
}

  • 创建talk接口的实现类
public class Student implements Talk{
    @Override
    public void talk() {
        System.out.println("【交谈中。。。】");
    }
}

  • 创建talk接口的增强代理类
  1. 通过执行Proxy.newProxyInstance()方法拿到一个代理对象;
  2. 重写接口InvocationHandler的invoke()方法编写具体的增强逻辑。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TalkProxyByJdk {

    public static Object getProxy(Object target){
        Object proxy = Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * @param proxy  增强后的代理对象
                     * @param method 需要代理增强的方法
                     * @param args   需要代理增强的方法的参数
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开始说话的时间:"+System.currentTimeMillis());
                        Object result = method.invoke(target, args);
                        System.out.println("停止说话的时间:"+System.currentTimeMillis());
                        return result;
                    }
                }
        );
        return proxy;
    }

}

  • 测试代理对象
import java.lang.reflect.Proxy;
public class TestJdkProxy {
   public static void main(String[] args) {
       // 创建初始对象 
        Talk student = new Student();
       // 创建代理对象 
        Talk proxy = (Talk) TalkProxyByJdk2.getProxy(student);
       // 执行代理对象的增强方法 
        proxy.talk();
    }
}

你可能感兴趣的:(java)