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

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

目录


本文的主要内容如下:

1dc618a0ed9580ce8bfa6facb208c08f.png


一、使用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();
    }


运行结果:


5d4c6812c8535adbb050f4ddf2e1bce8.png

显示aop已经生效。


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


看下aop自动配置的类:

46a9d80a6e05e4e3b19d57a0ee70bcdf.png


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


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的控制台打印看下:

1dc618a0ed9580ce8bfa6facb208c08f.png

这里也说明我们的确是使用的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();
    }
}


运行,控制台打印:


1dc618a0ed9580ce8bfa6facb208c08f.png

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


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


三、使用aop获取切面参数


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

5d4c6812c8535adbb050f4ddf2e1bce8.png

这里有上面几个方法,可以通过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();
    }
}


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


1dc618a0ed9580ce8bfa6facb208c08f.png

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


四、EnableAspectJAutoProxy获取代理对象


看下这个类的源码:

5d4c6812c8535adbb050f4ddf2e1bce8.png


有2个属性:


proxyTargetClass: 这个属性也可以切换动态代理方式,true代表cglib,false是jdk动态代理


exposeProxy: 这个属性设置为true可以获取到代理对象是谁。

设置为true,可以获取到AopContext对象:

1dc618a0ed9580ce8bfa6facb208c08f.png


现在测试下:

修改织入类:


@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();
    }
}


运行,控制台打印如下:


5d4c6812c8535adbb050f4ddf2e1bce8.png

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


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


相关文章
|
20天前
|
监控 Java 调度
SpringBoot中@Scheduled和Quartz的区别是什么?分布式定时任务框架选型实战
本文对比分析了SpringBoot中的`@Scheduled`与Quartz定时任务框架。`@Scheduled`轻量易用,适合单机简单场景,但存在多实例重复执行、无持久化等缺陷;Quartz功能强大,支持分布式调度、任务持久化、动态调整和失败重试,适用于复杂企业级需求。文章通过特性对比、代码示例及常见问题解答,帮助开发者理解两者差异,合理选择方案。记住口诀:单机简单用注解,多节点上Quartz;若是任务要可靠,持久化配置不能少。
165 4
|
5月前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
247 6
|
3月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
244 79
|
3月前
|
安全 API
鸿蒙开发:实现AOP代码插桩能力
正确的运用AOP,可以提升代码的模块化、复用性、可维护性和灵活性,同时降低了耦合度,使系统更易于扩展和维护。
89 13
鸿蒙开发:实现AOP代码插桩能力
|
2月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
229 5
|
3月前
|
Java Spring
SpringBoot自动配置原理
本文深入解析了SpringBoot的核心功能——自动配置,重点探讨了`org.springframework.boot.autoconfigure`及相关注解的工作机制。通过分析`@SpringBootApplication`、`@EnableAutoConfiguration`等注解,揭示了SpringBoot如何基于类路径和条件自动装配Bean
134 7
|
4月前
|
Java Spring
SpringBoot 实战 不同参数调用不同实现
本文介绍了如何在实际工作中根据不同的入参调用不同的实现,采用`map+enum`的方式实现优雅且严谨的解决方案。通过Spring Boot框架中的工厂模式或策略模式,避免了使用冗长的`if...else...`语句。文中详细展示了定义接口、实现类、枚举类以及控制器调用的代码示例,确保用户输入的合法性并简化了代码逻辑。
SpringBoot 实战 不同参数调用不同实现
|
3月前
|
Java
SpringBoot自动装配的原理
在SpringBoot项目的启动引导类上都有一个注解@SpringBootApplication 这个注解是一个复合注解, 其中有三个注解构成 , 分别是 ● @SpringBootConfiguration : 是@Configuration的派生注解 , 标注当前类是一个SpringBoot的配置类 ● @ComponentScan : 开启组件扫描, 默认扫描的是当前启动引导了所在包以及子包 ● @EnableAutoConfiguration : 开启自动配置(自动配置核心注解) 2.在@EnableAutoConfiguration注解的内容使用@Import注解导入了一个AutoC
|
2月前
|
安全 前端开发 Java
Spring Boot 项目中触发 Circular View Path 错误的原理与解决方案
在Spring Boot开发中,**Circular View Path**错误常因视图解析与Controller路径重名引发。当视图名称(如`login`)与请求路径相同,Spring MVC无法区分,导致无限循环调用。解决方法包括:1) 明确指定视图路径,避免重名;2) 将视图文件移至子目录;3) 确保Spring Security配置与Controller路径一致。通过合理设定视图和路径,可有效避免该问题,确保系统稳定运行。
143 0
|
3月前
|
JavaScript 前端开发 Java
Idea启动SpringBoot程序报错:Veb server failed to start. Port 8082 was already in use;端口冲突的原理与解决方案
本文解决了Idea启动SpringBoot程序报错:Veb server failed to start. Port 8082 was already in use的问题,并通过介绍端口的使用原理和操作系统的端口管理机制,可以更有效地解决端口冲突问题,并确保Web服务器能够顺利启动和运行。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~