【SpringBoot】@EnableAspectJAutoProxy注解,在SpringBoot中设置proxyTargetClass不生效?

@EnableAspectJAutoProxy注解,在SpringBoot中设置proxyTargetClass不生效?

最近在SpringBoot中使用@EnableAspectJAutoProxy注解,好奇proxyTargetClass的作用,看了API文档说是用来切换jdk代理和cglib代理的,可以实际上设置true或者false都是cglib的代理,难道是SpringBoo的bug?

前置准备
  • 一个有接口的实现,理论上默认使用jdk的动态代理
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
    @Override
    public void login() {
        log.info("Interface Login...");
    }
}
  • 一个没有接口的实现,用的是cglib代理
@Service
@Slf4j
public class PlainLoginService {
    public void login() {
        log.info("Class Login...");
    }
}
  • Aspect切面配置
@Aspect
@Slf4j
public class FooAspect {

    @Pointcut("execution(* io.spring.action.aop.service..*.*(..))")
    public void pointcut() {
    }

    @After(value = "pointcut()")
    public void after() {
        log.info(this.getClass().toString());
        log.info("after login");
    }
}
SpringBoot环境
@SpringBootApplication
@Slf4j
// 指示是否创建基于子类(CGLIB)的代理,而不是创建基于标准Java接口的代理。 默认值是{@code false}。
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringAopApplicationDemo implements ApplicationRunner {

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

    // 定义切面,或者直接使用@Component注解
    @Bean
    public FooAspect fooAspect() {
        return new FooAspect();
    }

    // 有接口实现
    @Autowired
    LoginService loginService;

    // 无接口实现
    @Autowired
    PlainLoginService plainLoginService;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        log.info(loginService.getClass().toString()); // class io.spring.action.aop.service.impl.LoginServiceImpl$$EnhancerBySpringCGLIB$$d3171a1f
        loginService.login();

        log.info(plainLoginService.getClass().toString()); // class io.spring.action.aop.service.PlainLoginService$$EnhancerBySpringCGLIB$$5b51dab3
        plainLoginService.login();
    }
}

可以看到运行结果,proxyTargetClass设置为true,生成的依旧是cglib的代理类而不是jdk的代理

Spring环境
@Configuration
@ComponentScan
@EnableAspectJAutoProxy(proxyTargetClass = false)
@Slf4j
public class SpringApplicationDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringApplicationDemo.class);

        LoginService loginService = context.getBean(LoginService.class); //jdk
        PlainLoginService plainLoginService = context.getBean(PlainLoginService.class); // cglib
        log.info("jdk class name = {}", loginService.getClass()); 
        log.info("cglib class name = {}", plainLoginService.getClass()); 
    }

    @Autowired
    private LoginService loginService;

    // 定义切面,或者直接使用@Component注解
    @Bean
    public FooAspect fooAspect() {
        return new FooAspect();
    }
}
  • proxyTargetClass = true
jdk class name = class io.spring.action.aop.service.impl.LoginServiceImpl$$EnhancerBySpringCGLIB$$8808e216
cglib class name = class io.spring.action.aop.service.PlainLoginService$$EnhancerBySpringCGLIB$$1043a2aa
  • proxyTargetClass = false
jdk class name = class com.sun.proxy.$Proxy21
cglib class name = class io.spring.action.aop.service.PlainLoginService$$EnhancerBySpringCGLIB$$3b8f4e09
  1. 可以看出,在Spring的环境下设置为true生成的都是cglib的代理,设置为false,默认有接口实现的是jdk的动态代理,没有接口的是cglib代理
  2. 说明在Spring环境下是有作用的,应该是SpringBoot做了什么操作,修改了这个行为。
  3. SpringBoot什么东西会修改默认行为呢?很容易想到自动装配
AopAutoConfiguration
  1. 可以看到玄机在这个类里面,SpringBoot使用了Aop自动装配,将代理类默认设置成cglib的
  2. 另一方面,也看到能够修改这个行为的,是通过spring.aop.proxy-target-class 属性来控制,所以,如果期望使用jdk+ cglib这种方式,可以在yml配置文件中修改这个属性
  3. 这个规则是在SpringBoot2.0后改的,之前的版本和Spring的效果一致
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
		AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {

	}

}

为什么SpringBoot都要将代理默认成cglib的,它比jdk有哪些好处呢?

  • 实际上,jdk的代理类只能赋值给接口,不能赋值给具体实现,如果有人注入实现类,那么会导致启动报错,默认cglib避免了这种问题的发生
@Configuration
@ComponentScan
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Slf4j
public class SpringApplicationDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringApplicationDemo.class);

        LoginService loginService = context.getBean(LoginService.class); //jdk
        PlainLoginService plainLoginService = context.getBean(PlainLoginService.class); // cglib
        log.info("jdk class name = {}", loginService.getClass());
        log.info("cglib class name = {}", plainLoginService.getClass());

    }

    //Bean named 'loginServiceImpl' is expected to be of type 'io.spring.action.aop.service.impl.LoginServiceImpl' but was actually of type 'com.sun.proxy.$Proxy21'
    // AOP代理对象如果使用jdk代理,只能赋值给接口,不能赋值给实现
    // SpringBoot中出于这个考虑,将所有代理对象默认为cglib
    @Autowired
	private LoginServiceImpl loginService;

    // 定义切面,或者直接使用@Component注解
    @Bean
    public FooAspect fooAspect() {
        return new FooAspect();
    }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: @enableaspectjautoproxy(exposeproxy = true) 是一个注解,用于启用 AspectJ 自动代理功能,并暴露代理对象。在 Spring AOP ,通过该注解可以将代理对象暴露出来,方便在 AOP 切面获取代理对象并进行操作。exposeproxy = true 表示暴露代理对象。 ### 回答2: @enableaspectjautoproxy(exposeproxy=true)是Spring AOP框架的一个注解,它可用于自动创建AspectJ代理并将其公开作为Spring bean,以便在需要时访问代理对象。 在默认情况下,Spring AOP使用JDK动态代理来创建代理对象。但是,如果被代理的目标对象没有实现任何接口,就无法使用JDK动态代理。在这种情况下,Spring AOP会切换到使用AspectJ实现的动态代理。 @EnableAspectJAutoProxy注解告诉Spring AOP框架在必要时启用AspectJ代理,并公开代理对象以供使用。此外,exposeproxy = true参数告诉Spring在代理创建过程将代理对象公开为Spring bean。这大大简化了代码访问代理对象的过程。 使用@enableaspectjautoproxy(exposeproxy = true)需要注意以下几点: - 该注解需要声明在配置类。 - 如果没有显式地指定proxy-target-class属性,Spring会自动检查目标bean类是否实现了至少一个接口。如果没有,将使用AspectJ运行时代理(CGLIB)。 - 由于代理创建是在运行时发生的,因此应该确保在运行时注入的所有依赖项都可以解析。否则可能会出现空指针异常或依赖项找不到的情况。 - 对于指定了“proxytargetclass = true”的情况,AspectJ代理将被始终使用,无论目标bean是否实现了至少一个接口。 总之,@enableaspectjautoproxy (exposeproxy = true)是一种方便的方法,在需要时访问AspectJ代理对象。它简化了代码并提供了更多的灵活性和可重用性。 ### 回答3: @enableaspectjautoproxy注解是Spring AOP框架用于标记类的注解,它的作用是开启自动代理,同时暴露代理对象,以便在需要时可以直接访问代理对象。 当使用@EnableAspectJAutoProxy注解时,Spring框架会自动为标记了@Aspect注解的切面类生成代理对象,并将它们添加到IOC容器。这些代理对象会拦截目标对象的方法调用,执行相关的切面逻辑,并最终将方法调用委托给目标对象。 exposeproxy = true参数告诉Spring框架,希望将代理对象暴露出来。这意味着我们可以直接使用代理对象,而无需进行类型转换或其他额外的处理。这对于在AOP切面获取代理对象,以便在切面方法进行一些特殊的操作非常有用。 除了exposeproxy参数外,@EnableAspectJAutoProxy注解还支持其他一些参数,比如proxytargetclass和order等。其proxytargetclass参数用于指定是否使用CGLib代理,而order参数用于指定多个切面的执行顺序。 总之,@EnableAspectJAutoProxy注解是Spring AOP框架一个非常重要的注解,它可以极大地简化AOP编程,并帮助我们更轻松地实现切面逻辑。同时,通过设置不同的参数,我们还可以进一步控制代理的行为,并满足不同的业务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值