您的位置:首页 > 编程语言 > Java开发

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文件中导入下面的依赖:

<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代理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: