动态代理和Spring Aop

时间:2019-02-16
本文章向大家介绍动态代理和Spring Aop,主要包括动态代理和Spring Aop使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1.动态代理

在静态代理中,每个被代理的类都需要单独定义一个代理类,当业务庞大时,代理类的代码也会很庞大,造成重复代码很多,不好维护。

相对于静态代理而言,动态代理可以将代理类的代码集中起来,让同一个类的不同方法,不同类的不同方法都会汇集在一起,方便对一些业务逻辑进行集中处理。

例如:https://www.zhihu.com/question/20794107/answer/75164285

1.1 JDK的动态代理

JDK的动态代理可以基于 java.lang.reflect.InvocationHandler定义,举例说明

1.创建一个接口

public interface StudentInterface {

    public void goToSchool();

}

2.创建一个InvocationHandler.  如果接口有实现类,可以在创建InvocationHandler的时候传一个实现类的对象

public class StudentInvocationHandler implements InvocationHandler {

    private Object target;
    
    public StudentInvocationHandler(){}

    public StudentInvocationHandler(Object target){
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //method.invoke(target, args); //执行被代理的对象的方法
        System.out.println("这是InvocationHandler中的invoke方法!");
        return null;
    }
}

3. 创建代理类 

InvocationHandler invocationHandler = new StudentInvocationHandler();
StudentInterface studentInterface = (StudentInterface) Proxy.newProxyInstance
        (StudentInterface.class.getClassLoader(),
                new Class[]{StudentInterface.class}, invocationHandler);
studentInterface.goToSchool();

例子中没有写StudentInterface接口的实现类,但是却可以通过动态代理创建 StudentInterface对象,其实Mybatis的Mapper接口就是这样的,编程的时候没有实现Mapper接口,但是却可以获取到Mapper接口的对象,其实真正获取到的对象就是代理对象.

调用studentInterface的所有方法都会跳到   StudentInvocationHandler 的  invoke方法中,可以在invoke方法中编写自己的业务逻辑。

如2中所说,可以在创建InvocationHandler的时候传入 实现类的对象,然后就可以在invoke方法中执行被代理的对象的方法。

1.2 基于cglib的动态代理

1.创建  MethodInterceptor

public class StudentCglib implements MethodInterceptor {

    private Object target;

    public StudentCglib(Object target){
        this.target = target;
    }

    public StudentCglib(){}

    public Object intercept(Object o, Method method, Object[] objects,
                            MethodProxy methodProxy) throws Throwable {
        System.out.println("到了MethodInterceptor的 intercept方法, 这是基于cglib的动态代理");
        //method.invoke(target, objects);
        return null;
    }

    public Object getInstance(Class originClass){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(originClass);
        enhancer.setCallback(this);
        return enhancer.create();
    }
}

2.创建代理类

StudentCglib studentCglib = new StudentCglib();
        StudentInterface studentProxy = (StudentInterface)
                studentCglib.getInstance(StudentInterface.class);
        studentProxy.goToSchool();

代理类实际上是 在 MethodInterceptor 中的 getInstance方法中用 Enhancer创建的,参数没有限制必须要是接口,所以是不必基于接口的。

2.Spring Aop

spring的Aop其实就是基于动态代理的,动态代理可以实现将分散的代码集中,和Aop的思想是一致的。

Spring 可以在配置文件中利用aop标签进行配置,还可以基于aspectj,在java代码中进行配置,这种方法更加简洁明了。

利用aspectj配置时,注意要在配置文件中加上

<aop:aspectj-autoproxy/>

Spring在创建代理对象的时候,会判断被代理的类时候实现了接口,如果实现了接口就使用JDK的动态代理,否则就使用cglib的动态代理。

org.springframework.aop.framework.DefaultAopProxyFactory 

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }