0
点赞
收藏
分享

微信扫一扫

springboot2原理实战(17)--aop开发必知必会


文章目录

  • ​​目录​​
  • ​​一、使用aop小demo认识开发流程​​
  • ​​1:spring-boot-start-aop 加入依赖,默认开启了Aop的支持​​
  • ​​2:写一个Aspect,封装横切关注点(日志,监控等待),需要配置前置通知,后置通知等待,和切入点,哪些包的哪些类的方法等等​​
  • ​​3.测试:​​
  • ​​二、了解springboot的代理和切换代理操作​​
  • ​​1.默认的动态代理cglib​​
  • ​​2.切换成jdk动态代理​​
  • ​​三、使用aop获取切面参数​​
  • ​​四、EnableAspectJAutoProxy获取代理对象​​

目录

本文的主要内容如下:

springboot2原理实战(17)--aop开发必知必会_动态代理

一、使用aop小demo认识开发流程

1:spring-boot-start-aop 加入依赖,默认开启了Aop的支持

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

写个被切入的类:

@Repository
public class UserDao {
public void add(String username, String password){
System.out.println("add 【username:"+username+",password:"+password+"】");
}
}

2:写一个Aspect,封装横切关注点(日志,监控等待),需要配置前置通知,后置通知等待,和切入点,哪些包的哪些类的方法等等

​这个Aspect需要@Component纳入到spring容器管理,并且需要纳入spring管理​​:

@Aspect
@Component
public class LogAspect {

@Before("execution(* com.springboot.demo17.dao..*.*(..))")
public void log(){
// System.out.println("before method log done "+ AopContext.currentProxy().getClass());
System.out.println("before method log done");
}
}

3.测试:

@SpringBootApplication
public class Demo17Application {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Demo17Application.class, args);
System.out.println(context.getBean(UserDao.class).getClass());

context.getBean(UserDao.class).add("admin","123");
context.close();
}

运行结果:

springboot2原理实战(17)--aop开发必知必会_spring_02


显示aop已经生效。

二、了解springboot的代理和切换代理操作

看下aop自动配置的类:

springboot2原理实战(17)--aop开发必知必会_spring boot_03

通过源码,我们可以看到,

  • 1.spring.aop", name = “auto”, havingValue = “true”,说明springboot默认为我们开启Aop我们可以通过这个spring.auto来设置是否开启关闭。
  • 2.springboot2默认是使用的cglib代理。我们可以使用spring.aop.proxy-target-class的true和fasle,来切换代理模式是cglib还是jdk动态代理。true代表cglib,false代表jdk动态代理。

1.默认的动态代理cglib

刚才的aop入门小demo的控制台打印看下:

springboot2原理实战(17)--aop开发必知必会_spring_04


这里也说明我们的确是使用的cglib

2.切换成jdk动态代理

我们知道jdk动态代理是面向接口的,现在设置下:
写一个接口:

public interface IuserDao {
public void add(String username, String password);
}

@Repository
public class UserDao implements IuserDao{

public void add(String username, String password){
System.out.println("add 【username:"+username+",password:"+password+"】");
}
}

配置文件修改动态代理方式:

spring.aop.auto=true
spring.aop.proxy-target-class=false

打印查看:

@SpringBootApplication
public class Demo17Application {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Demo17Application.class, args);
System.out.println(context.getBean(UserDao.class).getClass());
//
context.getBean(UserDao.class).add("admin","123");
context.close();
}
}

测试类:

@SpringBootApplication
public class Demo17Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Demo17Application.class, args);
//得用接口获取对象
System.out.println(context.getBean(IuserDao.class).getClass());
context.getBean(IuserDao.class).add("admin","123");
context.close();
}
}

运行,控制台打印:

springboot2原理实战(17)--aop开发必知必会_spring_05


显示已经是java的jdk动态代理了。

​特别注意​​: UserDao必须实现个IUserDao的接口,必须通过接口获取实例,不然使用的还是cglib动态代理。

三、使用aop获取切面参数

拿到切面里面的类或者参数,可以通过JoinPoint point

springboot2原理实战(17)--aop开发必知必会_jdk动态代理_06


这里有上面几个方法,可以通过getTarget获取类,getArgs获取方法的参数,getSignature().获取方法名称。

测试下:

改下编织类,添加个after后置织入:

@Aspect
@Component
public class LogAspect {

@Before("execution(* com.springboot.demo17.dao..*.*(..))")
public void log(){
// System.out.println("before method log done "+ AopContext.currentProxy().getClass());
System.out.println("before method log done");
}
@After("execution(* com.springboot.demo17.dao..*.*(..))")
public void logAfter(JoinPoint point){
System.out.println("after method log done"+point.getTarget().getClass()+",args="+ Arrays.asList(point.getArgs())+",method="+point.getSignature().getName());
}

}

测试:

@SpringBootApplication
public class Demo17Application {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Demo17Application.class, args);
System.out.println(context.getBean(UserDao.class).getClass());
//
context.getBean(UserDao.class).add("admin","123");
context.close();
}
}

运行入口函数,控制台打印:

springboot2原理实战(17)--aop开发必知必会_spring_07


显示切面里面的类和参数和方法名都已经获取到了。

四、EnableAspectJAutoProxy获取代理对象

看下这个类的源码:

springboot2原理实战(17)--aop开发必知必会_spring boot_08


有2个属性:

  • proxyTargetClass: 这个属性也可以切换动态代理方式,true代表cglib,false是jdk动态代理
  • exposeProxy: 这个属性设置为true可以获取到代理对象是谁。
    设置为true,可以获取到AopContext对象:
  • springboot2原理实战(17)--aop开发必知必会_spring boot_09

现在测试下:
修改织入类:

@Aspect
@Component
public class LogAspect {

@Before("execution(* com.springboot.demo17.dao..*.*(..))")
public void log(){
System.out.println("before method log done "+ AopContext.currentProxy().getClass());
System.out.println("before method log done");
}
}

入口函数,设置可获取代理对象:​​@EnableAspectJAutoProxy(exposeProxy = true)​​:

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

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Demo17Application.class, args);
System.out.println(context.getBean(UserDao.class).getClass());
//
context.getBean(UserDao.class).add("admin","123");
context.close();
}
}

运行,控制台打印如下:

springboot2原理实战(17)--aop开发必知必会_动态代理_10


可以看到,代理对象是:EnhancerBySpringCGLIB.

本文,主要讲laop如何使用,如何切换动态代理,如何拿到动态代理的参数,如何获取代理对象。

个人微信公号:

搜索: 怒放de每一天

不定时推送相关文章,期待和大家一起成长!!

springboot2原理实战(17)--aop开发必知必会_jdk动态代理_11


举报

相关推荐

0 条评论