Spring 代理对象,cglib,jdk的问题思考,AOP 配置注解拦截 的一些问题.为什么不要注解在接口,以及抽象方法.
可以被继承
首先注解在类上是可以被继承的 在注解上用@Inherited
/**
* 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代理对象/非代理对象)
注解在方法中,没有所谓继承问题,只有重写问题(什么时候会被重写,除了人为重写,还有产生代理对象的时候会被重写)
如果注解在父类方法中,如果方法没有被子类重写,那么调用的是父类的方法,那么注解是存在的,如果方法被子类重写,子类方法没有注解,那么调用子类方法就获取不了注解
测试前请确保开启了(exposeProxy = true),此参数暴露代理对象,否则AopContext.currentProxy()会抛出以下异常
java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.
不过就算开启了exposeProxy = true,在非代理对象中使用AopContext.currentProxy(),同样会抛出
在SpringBoot中使用注解开启
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class AopApplication
继承抽象类非代理对象
非代理对象测试代码:
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);
} }
结果
代理对象(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 也是获取不了注解的.因为方法不能被代理对象重写.
Spring 代理对象,cglib,jdk的问题思考,AOP 配置注解拦截 的一些问题.为什么不要注解在接口,以及抽象方法.的更多相关文章
- AOP 如果被代理对象的方法设置了参数 而代理对象的前置方法没有设置参数 则无法拦截到
AOP 如果被代理对象的方法设置了参数 而代理对象的前置方法没有设置参数 则无法拦截到
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
spring-aop-4.3.7.RELEASE 在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...
- Spring代理模式(jdk动态代理模式)
有动态代理和静态代理: 静态代理就是普通的Java继承调用方法. Spring有俩种动态代理模式:jdk动态代理模式 和 CGLIB动态代理 jdk动态代理模式: 代码实现: 房东出租房子的方法(继承 ...
- (转载,但不知道谁原创)获取SPRING 代理对象的真实实例,可以反射私有方法,便于测试
/** * 获取 目标对象 * @param proxy 代理对象 * @return * @throws Exception */ public static Object getTarget(Ob ...
- SpringBoot CGLIB AOP解决Spring事务,对象调用自己方法事务失效.
对于像我这种喜欢滥用AOP的程序员,遇到坑也是习惯了,不仅仅是事务,其实只要脱离了Spring容器管理的所有对象,对于SpringAOP的注解都会失效,因为他们不是Spring容器的代理类,Sprin ...
- Java中如何实现代理机制(JDK动态代理和cglib动态代理)
http://blog.csdn.net/skiof007/article/details/52806714 JDK动态代理:代理类和目标类实现了共同的接口,用到InvocationHandler接口 ...
- 浅谈Spring中JDK动态代理与CGLIB动态代理
前言Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式, ...
- Spring声明式事务的实现方式选择(JDK动态代理与cglib)
1.简介 Spring声明式事务的具体实现方式是动态决定的,与具体配置.以及事务代理对象是否实现接口等有关. 2.使用JDK动态代理的情况 在满足下面两个条件时,Spring会选择JDK动态代理作为声 ...
- 深入理解Spring AOP之二代理对象生成
深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...
随机推荐
- 比较Maven和Ant
从今天开始,整理maven一系列. Maven 它是什么? 如何回答这个问题要看你怎么看这个问题. 绝大部分Maven用户都称Maven是一个"构建工具":一个用来把源代码构建成可 ...
- linkin大话设计模式--建造模式
linkin大话设计模式--建造模式 建造模式是对象的创建模式,可以讲一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象. 建造模式的结构: 抽象建造者 ...
- weex 启动 android 模拟器(mac环境)
一.android studio和android sdk下载 1.android studio下载并安装https://developer.android.com/studio/index.html ...
- lvs_dr
lvs_dr 实验需求(4台虚拟机) eth0 192.168.1.110 单网卡 client(可以使用windows浏览器代替,但会有缓存影响) eth0 192.168.1.186 单网卡 di ...
- Python类的__getitem__和__setitem__特殊方法
class testsetandget: kk = {}; def __getitem__(self, key): return self.kk[key]; ...
- 【转】shell:date 常用方式
在linux下获取时间字符串 命令 date # 以yyyymmdd格式输出23天之前现在这个时刻的时间 $ date +%Y%m%d –date=’23 days ago’ $ date -u Th ...
- Eclipse运行Java简单实例
运行eclipse前首先配置好JDK环境变量等 双击这句话可跳转配置环境变量详细步骤 运行eclipse软件 1.File菜单-New - project 2.Java Project - Next ...
- java indexof、BigDecimal、字符串替换
自我总结,有什么需要改正弥补的地方,请指出,感激不尽! 本次总结了indexof的用法,BigDecimal的乘法.移位运算,Decimal的格式化输出,字符串替换 上代码: 测试类 Test.jav ...
- Linux面试题(2)
一.Linux操作系统知识 1.常见的Linux发行版本都有什么?你最擅长哪一个?它的官网网站是什么?说明你擅长哪一块? Centos,Ubunto,fedora,openSUSE,Debian等,擅 ...
- 基于线程池的线程管理(BlockingQueue生产者消费者方式)实例
1.线程池管理类: public class ThreadPoolManager { private static ThreadPoolManager instance = new ThreadPoo ...