Spring 代理对象,cglib,jdk的问题思考,AOP 配置注解拦截 的一些问题.为何不要注解在接口,以及抽象方法.

能够被继承

 

首先注解在类上是能够被继承的 在注解上用@Inheritedjava

/**
 * Created by laizhenwei on 17:49 2017-10-14
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited public @interface Mark {
    String desc() default "";
}

注解在方法上(jdk代理对象/cglib代理对象/非代理对象)

 

注解在方法中,没有所谓继承问题,只有重写问题(何时会被重写,除了人为重写,还有产生代理对象的时候会被重写)
若是注解在父类方法中,若是方法没有被子类重写,那么调用的是父类的方法,那么注解是存在的,若是方法被子类重写,子类方法没有注解,那么调用子类方法就获取不了注解spring

测试前请确保开启了(exposeProxy = true),此参数暴露代理对象,不然AopContext.currentProxy()会抛出如下异常ide

java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.

不过就算开启了exposeProxy = true,在非代理对象中使用AopContext.currentProxy(),一样会抛出测试

在SpringBoot中使用注解开启ui

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class AopApplication 

 继承抽象类非代理对象spa

非代理对象测试代码:3d

package com.example.aop.aopproxy.cglibproxy;

import com.example.aop.annotation.aopproxy.Mark;

/**
 * Created by laizhenwei on 17:56 2017-10-14
 */
@Mark(desc = "我是被注解在抽象类中的Mark!")
public abstract class AbstractClass {
    @Mark
    public abstract void sysout();

    /**
     * 此方法继承之后,子类没有重写,因此能够获取到注解(此结论仅针对非代理对象,以及jdk动态代理对象(不针对cglib代理对象))
     */
    @Mark
    public void sysout2(){
        System.out.println("sysout2");
    }

    public abstract boolean isAopProxy();


    public abstract boolean isCglibProxy();

    public abstract boolean isJdkDynamicProxy();
}
package com.example.aop.aopproxy.cglibproxy.impl;

import com.example.aop.aopproxy.cglibproxy.AbstractClass;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.support.AopUtils;

/**
 * Created by laizhenwei on 17:57 2017-10-14
 */
public class ClassImplNoProxy extends AbstractClass {
    @Override
    public void sysout() {

    }

    @Override
    public boolean isAopProxy(){
        return AopUtils.isAopProxy(AopContext.currentProxy());
    }


    @Override
    public boolean isCglibProxy(){
        return AopUtils.isCglibProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isJdkDynamicProxy(){
        return AopUtils.isJdkDynamicProxy(AopContext.currentProxy());
    }
}

JunitTest代理

package com.example.aop.aopproxy.cglibproxy;

import com.example.aop.AopApplication;
import com.example.aop.annotation.aopproxy.Mark;
import com.example.aop.aopproxy.cglibproxy.impl.ClassImplNoProxy;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * Created by laizhenwei on 17:58 2017-10-14
 * 非代理类测试,继承抽象类
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AopApplication.class)
public class AbstractClassTestsNoProxy {
    /**
     * 实现类接收
     * 这里直接new 出来一个非代理对象,不采用Spring 注入,
     */
    private ClassImplNoProxy notProxyClassImpl = new ClassImplNoProxy();
    /**
     * 抽象类接收
     * 这里直接new 出来一个非代理对象,不采用Spring 注入,
     */
    private AbstractClass abstractClass = new ClassImplNoProxy();

    /**
     * 测试是否代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isProxy(){
        try {
            System.out.println( notProxyClassImpl.isAopProxy());
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }


    /**
     * 测试是否cglib代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isCglibProxy(){
        try {
            System.out.println(notProxyClassImpl.isCglibProxy());
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }

    /**
     * 测试是否JDK动态代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isJdkDynamicProxy(){
        try {
            System.out.println(notProxyClassImpl.isJdkDynamicProxy());;
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }

    //方法被重写,mark 为null
    @Test
    public void getSysoutMark() throws NoSuchMethodException {
        Mark mark = notProxyClassImpl.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull(mark);
    }

    //方法被重写,mark 为null
    @Test
    public void getAbstractClassSysoutMark() throws NoSuchMethodException {
        Mark mark = abstractClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull("方法被重写,mark 为null",mark);
    }

    //方法没有重写,测试经过
    @Test
    public void getSysout2Mark() throws NoSuchMethodException {
        Mark mark = notProxyClassImpl.getClass().getMethod("sysout2",null).getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //方法没有重写,测试经过
    @Test
    public void getAbstractClassSysout2Mark() throws NoSuchMethodException {
        Mark mark = abstractClass.getClass().getMethod("sysout2",null).getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //注解在类上是能够继承的
    @Test
    public void getImplClassMark(){
        Mark mark = notProxyClassImpl.getClass().getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

}

结果code

 

代理对象(CGLIB):对象

咱们来修改子类改成Spring注入方式

 

package com.example.aop.aopproxy.cglibproxy.impl;

import com.example.aop.aopproxy.cglibproxy.AbstractClass;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Service;

/**
 * Created by laizhenwei on 18:25 2017-10-14
 */
@Service("cglibClassImplProxy")
public class CglibClassImplProxy extends AbstractClass {
    @Override
    public void sysout() {

    }

    @Override
    public boolean isAopProxy(){
        return AopUtils.isAopProxy(AopContext.currentProxy());
    }


    @Override
    public boolean isCglibProxy(){
        return AopUtils.isCglibProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isJdkDynamicProxy(){
        return AopUtils.isJdkDynamicProxy(AopContext.currentProxy());
    }

}

 

junitTest 看看有没有惊喜

package com.example.aop.aopproxy.cglibproxy;

import com.example.aop.AopApplication;
import com.example.aop.annotation.aopproxy.Mark;
import com.example.aop.aopproxy.cglibproxy.impl.CglibClassImplProxy;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * Created by laizhenwei on 18:24 2017-10-14
 * 代理对象
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AopApplication.class)
public class AbstractClassTestsProxy {
    @Resource(name = "cglibClassImplProxy")
    private CglibClassImplProxy cglibClassProxy;
    //抽象类接收
    @Resource(name = "cglibClassImplProxy")
    private AbstractClass abstractClass;

    /**
     * 测试是否代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isProxy(){
        try {
            System.out.println( cglibClassProxy.isAopProxy());
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }


    /**
     * 测试是否cglib代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isCglibProxy(){
        try {
            System.out.println(cglibClassProxy.isCglibProxy());
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }

    /**
     * 测试是否JDK动态代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isJdkDynamicProxy(){
        try {
            System.out.println(cglibClassProxy.isJdkDynamicProxy());;
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }

    //方法被重写,mark 为null
    @Test
    public void getSysoutMark() throws NoSuchMethodException {
        Mark mark = cglibClassProxy.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull(mark);
    }

    //方法被重写,mark 为null
    @Test
    public void getAbstractClassSysoutMark() throws NoSuchMethodException {
        Mark mark = abstractClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull("方法被重写,mark 为null",mark);
    }

    //方法没有重写,测试经过
    @Test
    public void getSysout2Mark() throws NoSuchMethodException {
        Mark mark = cglibClassProxy.getClass().getMethod("sysout2",null).getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //方法没有重写,测试经过
    @Test
    public void getAbstractClassSysout2Mark() throws NoSuchMethodException {
        Mark mark = abstractClass.getClass().getMethod("sysout2",null).getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //注解在类上是能够继承的
    @Test
    public void getImplClassMark(){
        Mark mark = cglibClassProxy.getClass().getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }
}

结果

依然所有经过,这不科学,使用了Spring bean 注入方式,依然获取不到代理对象(由于isProxy ,isCglibProxy , isJdkDynamicProxy依然抛出了异常)

缘由是:spring会根据当前对象,判断是否建立jdk动态代理的代理对象(针对接口代理),仍是cglib的代理对象(针对实现类代理),或者不建立代理对象,在上面的测试中

子类,以及父类都没有须要使用Spring代理对象的必要(全部方法都没有使用到SpringAop),因此没有建立,这里须要一个代理对象来测试,因此给方法加上事务注解就行了

OK,知道缘由那就好办,咱们在子类或者父类随便一个方法加上事务注解这里在抽象类加上事务注解

package com.example.aop.aopproxy.cglibproxy;

import com.example.aop.annotation.aopproxy.Mark;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by laizhenwei on 17:56 2017-10-14
 */
@Mark(desc = "我是被注解在抽象类中的Mark!")
public abstract class AbstractClass {
    @Mark
  @Transactional public abstract void sysout();

    /**
     * 此方法继承之后,子类没有重写,因此能够获取到注解(此结论仅针对非代理对象,以及jdk动态代理对象(不针对cglib代理对象))
     */
    @Mark
    public void sysout2(){
        System.out.println("sysout2");
    }

    public abstract boolean isAopProxy();


    public abstract boolean isCglibProxy();

    public abstract boolean isJdkDynamicProxy();
}

修改测试类

package com.example.aop.aopproxy.cglibproxy;

import com.example.aop.AopApplication;
import com.example.aop.annotation.aopproxy.Mark;
import com.example.aop.aopproxy.cglibproxy.impl.CglibClassImplProxy;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * Created by laizhenwei on 18:24 2017-10-14
 * 代理对象
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AopApplication.class)
public class AbstractClassTestsProxy {
    @Resource(name = "cglibClassImplProxy")
    private CglibClassImplProxy cglibClassProxy;
    //抽象类接收
    @Resource(name = "cglibClassImplProxy")
    private AbstractClass abstractClass;

    /**
     * 测试是否代理对象
     */
    @Test
    public void isProxy(){
        Assert.assertTrue(cglibClassProxy.isAopProxy());
    }


    /**
     * 测试是否cglib代理对象
     */
    @Test
    public void isCglibProxy(){
        Assert.assertTrue(cglibClassProxy.isCglibProxy());
    }

    /**
     * 测试是否JDK动态代理对象
     */
    @Test
    public void isJdkDynamicProxy(){
        Assert.assertFalse(cglibClassProxy.isJdkDynamicProxy());
    }

    //方法被重写,mark 为null
    @Test
    public void getSysoutMark() throws NoSuchMethodException {
        Mark mark = cglibClassProxy.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull(mark);
    }

    //方法被重写,mark 为null
    @Test
    public void getAbstractClassSysoutMark() throws NoSuchMethodException {
        Mark mark = abstractClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull("方法被重写,mark 为null",mark);
    }

    //方法没有人为重写,测试不经过,由于 cglib代理对象已经被重写
    @Test
    public void getSysout2Mark() throws NoSuchMethodException {
        Mark mark = cglibClassProxy.getClass().getMethod("sysout2",null).getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //方法没有人为重写,测试不经过,由于 cglib代理对象已经被重写
    @Test
    public void getAbstractClassSysout2Mark() throws NoSuchMethodException {
        Mark mark = abstractClass.getClass().getMethod("sysout2",null).getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //注解在类上是能够继承的
    @Test
    public void getImplClassMark(){
        Mark mark = cglibClassProxy.getClass().getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }
}

 

JunitTest结果,这下成功生成代理对象,可是出现了两个预期外的结果.(测试代理对象三个方法的断言已经被修改,因此测试经过)

 

咱们在子类中,并无人为重写这个方法,为什么注解就获取不到了?不管用实现类接收,仍是抽象类接收.

缘由:继承抽象类的bean,Spring注入,不管如何都是cglib代理,针对实现类代理,因此会把父类的方法在子类中重写,这时并无带上注解.因此代理类中不管如何都获取不了注解

(这也就是为何注解在抽象类的方法中,aop拦截注解会失效的缘由)

 

实现接口(非代理对象 new)

package com.example.aop.aopproxy.jdkproxy;

import com.example.aop.annotation.aopproxy.Mark;

/**
 * Created by laizhenwei on 17:43 2017-10-14
 */
public interface IClass {

    @Mark
    void sysout();

    boolean isAopProxy();

    boolean isCglibProxy();

    boolean isJdkDynamicProxy();

}

实现类

package com.example.aop.aopproxy.jdkproxy.impl;

import com.example.aop.aopproxy.jdkproxy.IClass;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.support.AopUtils;

/**
 * Created by laizhenwei on 17:44 2017-10-14
 */
public class ClassImplNoProxy implements IClass {
    @Override
    public void sysout() {
    }

    @Override
    public boolean isAopProxy() {
        return AopUtils.isAopProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isCglibProxy() {
        return AopUtils.isCglibProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isJdkDynamicProxy() {
        return AopUtils.isJdkDynamicProxy(AopContext.currentProxy());
    }
}

junitTest

package com.example.aop.aopproxy.jdkproxy;

import com.example.aop.AopApplication;
import com.example.aop.annotation.aopproxy.Mark;
import com.example.aop.aopproxy.jdkproxy.impl.ClassImplNoProxy;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


/**
 * Created by laizhenwei on 17:46 2017-10-14
 */

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AopApplication.class)
public class IClassTestsNoProxy {
    /**
     * 实现类接收
     * 这里直接new 出来一个非代理对象,不采用Spring 注入,
     */
    private ClassImplNoProxy notProxyClassImpl = new ClassImplNoProxy();
    /**
     * 接口类接收
     * 这里直接new 出来一个非代理对象,不采用Spring 注入,
     */
    private IClass iClass = new ClassImplNoProxy();

    /**
     * 测试是否代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isProxy(){
        try {
            System.out.println( notProxyClassImpl.isAopProxy());
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }


    /**
     * 测试是否cglib代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isCglibProxy(){
        try {
            System.out.println(notProxyClassImpl.isCglibProxy());
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }

    /**
     * 测试是否JDK动态代理对象,这里采用new,这里必然会抛出异常
     */
    @Test
    public void isJdkDynamicProxy(){
        try {
            System.out.println(notProxyClassImpl.isJdkDynamicProxy());;
        }catch (Throwable throwable){
            Assert.assertNotNull(throwable);
            return;
        }
        Assert.assertTrue(false);//若是代码能执行到这里,断言失败
    }

    //方法被重写,mark 为null
    @Test
    public void getSysoutMark() throws NoSuchMethodException {
        Mark mark = notProxyClassImpl.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull(mark);
    }

    //方法被重写,mark 为null
    @Test
    public void getAbstractClassSysoutMark() throws NoSuchMethodException {
        Mark mark = iClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull("方法被重写,mark 为null",mark);
    }

    //注解在接口上,并非继承,因此获取不了
    @Test
    public void getImplClassMark(){
        Mark mark = notProxyClassImpl.getClass().getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

}

 

测试结果,其余都跟预期同样,可是获取不了实现类的注解, 想固然这是现实接口,不是继承.因此获取不了也合理.

实现接口(非代理对象 Spring 注入 bean) 注解@Service 让Spring容器管理,注释掉事务注解

 

package com.example.aop.aopproxy.jdkproxy.impl;

import com.example.aop.aopproxy.jdkproxy.IClass;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Service;

/**
 * Created by laizhenwei on 19:37 2017-10-14
 */
@Service("classImplProxy")
public class ClassImplProxy implements IClass {

    @Override
//    @Transactional
    public void sysout() {

    }

    @Override
    public boolean isAopProxy() {
        return AopUtils.isAopProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isCglibProxy() {
        return AopUtils.isCglibProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isJdkDynamicProxy() {
        return AopUtils.isJdkDynamicProxy(AopContext.currentProxy());
    }
}

 

JUNIT TEST  用注解获取bean

package com.example.aop.aopproxy.jdkproxy;

import com.example.aop.AopApplication;
import com.example.aop.annotation.aopproxy.Mark;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * Created by laizhenwei on 19:46 2017-10-14
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AopApplication.class)
public class IClassTestsProxy {
    /**
     * 实现类接收
     */
//    @Resource
////            @Autowired
//    private ClassImplProxy classImplProxy;
    /**
     * 接口类接收
     */
//    @Resource(name = "classImplProxy")
    @Resource(name = "classImplProxy")
    private IClass iClass;

    /**
     * 测试是否代理对象
     */
    @Test
    public void isProxy(){
        Assert.assertTrue(iClass.isAopProxy());
    }


    /**
     * 测试是否cglib代理对象
     */
    @Test
    public void isCglibProxy(){
        Assert.assertTrue(iClass.isCglibProxy());
    }

    /**
     * 测试是否JDK动态代理对象
     */
    @Test
    public void isJdkDynamicProxy(){
        Assert.assertTrue(iClass.isJdkDynamicProxy());
    }

    //方法被重写,mark 为null
    @Test
    public void getSysoutMark() throws NoSuchMethodException {
        Mark mark = iClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull(mark);
    }

    //方法被重写,mark 为null
    @Test
    public void getAbstractClassSysoutMark() throws NoSuchMethodException {
        Mark mark = iClass.getClass().getMethod("sysout",null).getAnnotation(Mark.class);
        Assert.assertNull("方法被重写,mark 为null",mark);
    }

    //注解在接口上,并非继承,因此获取不了
    @Test
    public void getImplClassMark(){
        Mark mark = iClass.getClass().getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

    //注解在接口上,并非继承,因此获取不了
    @Test
    public void getClassMark(){
        Mark mark = iClass.getClass().getAnnotation(Mark.class);
        Assert.assertNotNull(mark);
    }

}

测试结果(这里并无创代理对象,由于没有方法中并无使用到Aop 的方法,Spring断定没有必要建立代理对象)

加上事务注解

package com.example.aop.aopproxy.jdkproxy.impl;

import com.example.aop.aopproxy.jdkproxy.IClass;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by laizhenwei on 19:37 2017-10-14
 */
@Service("classImplProxy")
//@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public class ClassImplProxy implements IClass {

    @Override
    @Transactional
    public void sysout() {
    }

    @Override
    public boolean isAopProxy() {
        return AopUtils.isAopProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isCglibProxy() {
        return AopUtils.isCglibProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isJdkDynamicProxy() {
        return AopUtils.isJdkDynamicProxy(AopContext.currentProxy());
    }
}

测试结果(出乎意料,竟然是cglib代理,这里我作过几个测试,哪怕是实现了接口,依然是cglib代理,无解)

强制指定根据接口建立代理类,@Scope(proxyMode = ScopedProxyMode.INTERFACES)

package com.example.aop.aopproxy.jdkproxy.impl;

import com.example.aop.aopproxy.jdkproxy.IClass;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by laizhenwei on 19:37 2017-10-14
 */
@Service("classImplProxy")
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public class ClassImplProxy implements IClass {

    @Override
    @Transactional
    public void sysout() {
    }

    @Override
    public boolean isAopProxy() {
        return AopUtils.isAopProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isCglibProxy() {
        return AopUtils.isCglibProxy(AopContext.currentProxy());
    }

    @Override
    public boolean isJdkDynamicProxy() {
        return AopUtils.isJdkDynamicProxy(AopContext.currentProxy());
    }
}

测试结果 (没有变化)

 

可是就已经不能使用实现类接收

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.aop.aopproxy.jdkproxy.IClassTestsProxy': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'classImplProxy' is expected to be of type 'com.example.aop.aopproxy.jdkproxy.impl.ClassImplProxy' but was actually of type 'com.sun.proxy.$Proxy61'

 

 

基于全都是CGLIB 代理,可能有人怀疑我设置了强制走CGLIB 的代理参数,实际上并无

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class AopApplication {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    public static void main(String[] args) {
        SpringApplication.run(AopApplication.class, args);
    }
}



@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}

 

 

 结论:

原本想测试针对接口现实的jdk动态代理的bean,是能够注解在接口,注入对象可以获取到注解.但由于全程了cglib那么就没办法测了.

为何建议注解都在实现类方法上, 是由于有那么多不稳定的因素.

是否实现了接口就必定是jdk 代理, 不必定,还可能不建立

在一个类中,若是没有涉及aop的方法操做,那么Spring不会建立代理对象

若是继承了一个类,又现实了接口是什么状况呢?我测试过,也是cglib,可是如今也不敢保证必定是.

注解在static 方法,以及final aop 也是获取不了注解的.由于方法不能被代理对象重写.

相关文章
相关标签/搜索