11.1、spring boot中aop的应用
2018-01-01 18:29
471 查看
在spring boot工程中应用aop与在spring 工程中应用aop相似,可参考另两篇博客AOP的使用方法和AspectJ 切面注解中五种通知注解:@Before、@After、@AfterRunning、@AfterThrowing、@Around。下面只演示在spring boot中aop的应用。
在应用之前需要先导入aop的依赖,只需在pom.xml文件中导入下面的依赖:
UserDao 类:
切面类LogAop,其中定义前置通知方法logInfo():
spring boot工程的启动类为:
启动spring boot工程,输出如下:
从输出中可以看出,在执行add()时,先执行了切面的前置通知方法。
其中
从上面源码中可以看出,如果配置了
另外,如果要执行的目标方法所在类不是实现接口的类,即使在application.peoperties配置文件中配置了
启动启动类,输出
可见即使配置了
如果在定义目标类时,是实现的接口,把UserDao改成如下:
在application.properties中配置
运行启动类,输出
可见用的是jdk的动态代理实现aop
目标类UserDao:
切面类LogAop ,定义后置通知方法:
启动类:
运行启动类,输出
关于@EnableAspectJAutoProxy指定动态代理类,使用方法同上面讲的一样。如想用jdk动态代理,目标类必须要实现接口,否则还是使用的是cglib代理。
在应用之前需要先导入aop的依赖,只需在pom.xml文件中导入下面的依赖:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <relativePath /> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> </dependencies>
一、基本使用方法
下面以aop的前置通知为例,首先建一个dao层的类,在执行dao层中的方法前调用前置通知打印日志。UserDao 类:
package com.lzj.springboot.aop; import org.springframework.stereotype.Repository; @Repository public class UserDao { public void add(String name, String password){ System.out.println("name=" + name + ";password=" + password); } }
切面类LogAop,其中定义前置通知方法logInfo():
package com.lzj.springboot.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LogAop { /*定义前置通知方法*/ @Before(value="execution(* com.lzj.springboot.aop.UserDao.*(..))") public void logInfo(){ System.out.println("logInfo is executed before add() method"); } }
spring boot工程的启动类为:
@SpringBootApplication(scanBasePackages="com.lzj.springboot") public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); ConfigurableApplicationContext context = app.run(args); context.getBean(UserDao.class).add("lzj", "123456"); context.close(); } }
启动spring boot工程,输出如下:
logInfo is executed before add() method name=lzj;password=123456
从输出中可以看出,在执行add()时,先执行了切面的前置通知方法。
二、aop的开启和关闭配置属性
在spring boot工程中,aop默认是开启的,从spring-boot-autoconfigure的jar包下的org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.class配置类中源码可以看出:@Configuration @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.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 = true) public static class JdkDynamicAutoProxyConfiguration { } @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false) public static class CglibAutoProxyConfiguration { } }
其中
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)表示默认是配置
spring.aop.auto=true的,所以可在application.properties配置文件中配置
spring.aop.auto=true,也可以不配置,默认是开启的。如果想在spring boot工程中不启用aop,可以在application.properties配置文件中配置
spring.aop.auto=false。
三、aop的使用动态代理的配置属性
aop的实现用到了jdk的动态代理或者cglib的代理,可以在application.properties中配置使用哪种代理。如不配置默认使用的jdk的动态代理。还是从下面的源码看@Configuration @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.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 = true) public static class JdkDynamicAutoProxyConfiguration { } @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false) public static class CglibAutoProxyConfiguration { } }
从上面源码中可以看出,如果配置了
spring.aop.proxy-target-class=true表示使用cglib代理,如果配置了
spring.aop.proxy-target-class=false,表示使用了jdk的动态代理。因此可以在application.properties配置文件中配置
spring.aop.proxy-target-class=true来启动cglib代理实现aop,或者在application.properties配置文件中配置
spring.aop.proxy-target-class=false来启动jdk动态代理实现aop,如在application.peoperties文件中两者都不配置,默认使用jdk动态代理。
另外,如果要执行的目标方法所在类不是实现接口的类,即使在application.peoperties配置文件中配置了
spring.aop.proxy-target-class=false此时会默认使用cglib代理的。把基本使用方法章节中的启动类加上输出代理类的形式,如下:
@SpringBootApplication(scanBasePackages="com.lzj.springboot") public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); ConfigurableApplicationContext context = app.run(args); /*获取bean的class加载类*/ System.out.println(context.getBean(UserDao.class).getClass()); context.getBean(UserDao.class).add("lzj", "123456"); context.close(); } }
启动启动类,输出
class com.lzj.springboot.aop.UserDao$$EnhancerBySpringCGLIB$$f6b1762b logInfo is executed before add() method
可见即使配置了
spring.aop.proxy-target-class=false依然使用了cglib代理。
如果在定义目标类时,是实现的接口,把UserDao改成如下:
@Repository public class UserDao implements User{ @Override public void add(String name, String password) { System.out.println("name=" + name + ";password=" + password); } }
在application.properties中配置
spring.aop.proxy-target-class=false后,启动类改为通过接口的类型获取bean,如下:
@SpringBootApplication(scanBasePackages="com.lzj.springboot") public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); ConfigurableApplicationContext context = app.run(args); /*要通过接口的类型来获取bean,不可以通过UserDao.class*/ System.out.println(context.getBean(User.class).getClass()); /*不要写成UserDao.class*/ context.getBean(User.class).add("lzj", "123456"); context.close(); } }
运行启动类,输出
class com.sun.proxy.$Proxy60
logInfo is executed before add() method name=lzj;password=123456
可见用的是jdk的动态代理实现aop
四、可以在通知方法中获取目标类或目标方法的属性
下面以after后置通知方法为例目标类UserDao:
@Repository public class UserDao{ public void add(String name, String password) { System.out.println("name=" + name + ";password=" + password); } }
切面类LogAop ,定义后置通知方法:
package com.lzj.springboot.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LogAop { @After(value="execution(* com.lzj.springboot.aop.UserDao.*(..))") public void logAgter(JoinPoint jPoint){ System.out.println("目标类:" + jPoint.getTarget().getClass() + ";目标方法参数:" + Arrays.asList(jPoint.getArgs()) + ";目标方法名:" + jPoint.getSignature().getName()); } }
启动类:
@SpringBootApplication(scanBasePackages="com.lzj.springboot") public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); ConfigurableApplicationContext context = app.run(args); context.getBean(UserDao.class).add("lzj", "123456"); context.close(); } }
运行启动类,输出
name=lzj;password=123456 目标类:class com.lzj.springboot.aop.UserDao;目标方法参数:[lzj, 123456];目标方法名:add
五、@EnableAspectJAutoProxy用法
启动aop,可以不配置任何东西,默认启用aop,或者可以在application.properties配置文件中配置,像上面演示的示例一样。还有一种方法就是使用@EnableAspectJAutoProxy注解,在启动类上标注该注解,也表示启用了aop。并且还可以通过@EnableAspectJAutoProxy注解指定动态代理类,像下面形式 @SpringApplicationConfiguration(classes=DemoConfiguration.class) /*表示aop通过cglib代理来实现;如不指定proxyTargetClass属性,默认为false*/ @EnableAspectJAutoProxy(proxyTargetClass=true) public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); ConfigurableApplicationContext context = app.run(args); context.getBean(UserDao.class).add("lzj", "123456"); context.close(); } }
关于@EnableAspectJAutoProxy指定动态代理类,使用方法同上面讲的一样。如想用jdk动态代理,目标类必须要实现接口,否则还是使用的是cglib代理。
相关文章推荐
- springboot中aop应用
- Spring Boot使用AOP实现REST接口简易灵活的安全认证
- 【SpringBoot】Spring Boot进阶之Web进阶( 第2章 Web进阶-使用AOP处理请求 )
- Spring-Boot原理及应用布署
- 缺省配置Springboot Web应用运行中DispatchServlet的初始化
- SpringBoot学习笔记 - web开发(Thymeleaf的应用)
- Spring Boot应用的后台运行配置(转载)
- Spring AOP的应用
- 用Spring Boot颠覆Java应用开发
- AOP技术应用和研究--SpringAop实现原理
- 翻译-使用Ratpack和Spring Boot打造高性能的JVM微服务应用
- spring boot 拦截器 或 Spring AOP 方式记录请求日志
- Spring Boot (教程十二: AOP拦截器)
- Spring AOP 实现原理与 CGLIB 应用
- 使用Spring Boot快速构建应用
- SpringBoot之集成Spring AOP
- Spring Boot的应用启动与关闭的方法
- springboot整合kafka应用
- springboot配置aop切面详解
- 使用Spring的AOP进行缓存在遭遇Hibernate应用时的注意点