先看下这个问题的背景:假设有一个spring应用,开发人员希望自定义一个注解@Log,可以加到指定的方法上,实现自动记录日志(入参、出参、响应耗时这些)
package com.cnblogs.yjmyzz.springbootdemo.aspect; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Log { }
然后再写一个Aspect来解析这个注解,对打了Log注解的方法进行增强处理
package com.cnblogs.yjmyzz.springbootdemo.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Component @Aspect public class LogAspect { @Pointcut("execution (* com.cnblogs.yjmyzz.springbootdemo.service..*.*(..))") public void logPointcut() { } @Around("logPointcut()") public void around(JoinPoint point) { String methodName = point.getSignature().getName(); Object[] args = point.getArgs(); Class<?>[] argTypes = new Class[point.getArgs().length]; for (int i = 0; i < args.length; i++) { argTypes[i] = args[i].getClass(); } Method method = null; try { method = point.getTarget().getClass().getMethod(methodName, argTypes); } catch (Exception e) { e.printStackTrace(); } //获取方法上的注解 Log log = method.getAnnotation(Log.class); if (log != null) { //演示方法执行前,记录一行日志 System.out.println("before:" + methodName); } try { //执行方法 ((ProceedingJoinPoint) point).proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } finally { if (log != null) { //演示方法执行后,记录一行日志 System.out.println("after:" + methodName); } } } }
写一个测试Service类:
package com.cnblogs.yjmyzz.springbootdemo.service; import com.cnblogs.yjmyzz.springbootdemo.aspect.Log; import org.springframework.stereotype.Component; @Component public class HelloService { @Log public void sayHi(String msg) { System.out.println("/tsayHi:" + msg); } public void anotherSayHi(String msg) { this.sayHi(msg); } }
最后来跑一把:
package com.cnblogs.yjmyzz.springbootdemo; import com.cnblogs.yjmyzz.springbootdemo.service.HelloService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * @author 菩提树下的杨过 */ @ComponentScan("com.cnblogs.yjmyzz") @Configuration @EnableAspectJAutoProxy public class SampleApplication { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SampleApplication.class); HelloService helloService = context.getBean(HelloService.class); helloService.sayHi("hi-1"); System.out.println("/n"); helloService.anotherSayHi("hi-2"); } }
输出如下:
显然HelloService中的anotherSayHi方法,并未被aop增强。 原因其实很简单,了解AOP原理的同学想必都知道,AOP的实现有二类,如果是基于接口的,会采用动态代理,生成一个代理类,如果是基于类的,会采用CGLib生成子类,然后在子类中扩展父类中的方法。
本文中HelloService并不是一个接口,所以从上图的断点中可以看出,当Spring运行时,HelloService被增加为...EnhancerBySpringCGLib...。但是当调用到anotherSayHi时
方法的调用方,其实是原始的HelloSerfvice实例,即:是未经过Spring AOP增强的对象实例。所以解决问题的思路就有了,想办法用增强后的HelloService实例来调用!
这个方法,第一眼看上去感觉有些怪,自己注入自己,感觉有点象递归/死循环的搞法,但确实可以work,Spring在解决循环依赖上有自己的处理方式,避免了死循环。
原理与方法一其实类似,不多解释。
不过这个方法要注意的是,主类入口上,必须加上exporseProxy=true,参考下图:
最后来验证下这3种方法是否生效:
从运行结果上看,3种方法都可以解决这个问题。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
时间:2020-05-11
spring的事务控制本质上是通过aop实现的. 在springboot中使用时,可以通过注解@Transactional进行类或者方法级别的事务控制,也可以自己通过spring提供的事务管理器手动控制事务 一. @Transactional注解进行进行类或者方法级别的事务控制 不需要进行特别的设置,按照正常的配置整合spring和mybatis后,在需要进行事务控制的类上或者方法上加上 @Transactional注解,即可对其进行事务控制. 二.手动控制事务 当需要在一个方法的内部进行事务控
本文实例讲述了Spring AOP中定义切点的实现方法.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:
本文实例讲述了spring AOP定义AfterThrowing增加处理.分享给大家供大家参考,具体如下: 一 配置 <?xml version="1.0" encoding="GBK"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quo
这篇文章主要介绍了springboot配置aop切面日志打印过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.SpringBoot Aop说明 1. Aop AOP(Aspect-Oriented Programming,面向切面编程),它利用一种"横切"的技术,将那些多个类的共同行为封装到一个可重用的模块.便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性. 2. AOP相关概念: Aspect
检查下springboot的启动类是否开启扫描 @SpringBootApplication @ComponentScan(basePackages = {"com.zhangpu.springboot"}) 另外springboot默认开启的EnableAspectJAutoProxy为true 如果不放心可以增加: @EnableAspectJAutoProxy(proxyTargetClass=true) 第二种可能: 没有导入 相关的jar <dependency>
这篇文章主要介绍了Spring IOC和aop的原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.特点是面向接口编程,松耦合. 1:IOC(控制反转) 别名(DI:依赖注入) 首先来一段ioc的实现原来代码: public class ClassPathXmlApplicationContext implements BeanFactory { privat
这篇文章主要介绍了Spring AOP执行先后顺序实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 众所周知,spring声明式事务是基于AOP实现的,那么,如果我们在同一个方法自定义多个AOP,我们如何指定他们的执行顺序呢? 网上很多答案都是指定order,order越小越是最先执行,这种也不能算是错,但有些片面. 配置AOP执行顺序的三种方式: 通过实现org.springframework.core.Ordered接口 @Compo
操作日志对于程序员或管理员而言,可以快速定位到系统中相关的操作,而对于操作日志的管理的实现不能对正常业务实现进行影响,否则即不满足单一原则,也会导致后续代码维护困难,因此我们考虑使用AOP切面技术来实现对日志管理的实现. 文章大致内容: 1.基本概念 2.基本应用 3.日志管理实战 对这几部分理解了,会对AOP的应用应该很轻松. 一.基本概念 项目 描述 Aspect(切面) 跨越多个类的关注点的模块化,切面是通知和切点的结合.通知和切点共同定义了切面的全部内容--它是什么,在何时和何处完成其功
1.mysql数据库的组成与相关概念 首先明白,mysql是关系型数据库,和非关系型数据库中最大的不同就是表的概念不一样. +整个mysql环境可以理解成一个最大的数据库:A +用mysql创建的数据库B是属于A的,是数据的仓库,相当于系统中的文件夹 +数据表C:是存放数据的具体场所,相当于系统中的文件,一个数据库B中包含若干个数据表C(注意此处的数据库B和A不一样) +记录D:数据表中的一行称为一个记录,因此,我们在创建数据表时,一定要创建一个id列,用于标识"这是第几条记录",id
本文介绍了详解基于django实现的webssh简单例子,分享给大家,具体如下: 说明 新建一个 django 程序,本文为 chain. 以下仅为简单例子,实际应用 可根据自己平台情况 进行修改. 打开首页后,需要输入1,后台去登录主机,然后返回登录结果. 正常项目 可以post 主机和登录账户,进行权限判断,然后去后台读取账户密码,进行登录. djang后台 需要安装以下模块 安装后会有一个版本号报错,不影响 channels==2.0.2 channels-redis==2.1.0 amq
1 安装前准备: 1.1 安装JDK 卸载openjdk # rpm -qa | grep java # yum remove java-1.8.0-openjdk # yum remove java-1.8.0-openjdk-headless 安装JDK包 # rpm -ivh jdk-8u191-linux-x64.rpm 1.2 安装依赖包 # yum install -y net-snmp net-snmp-devel OpenIPMI-devel libssh2-dev
一.导入excel文件和相关库 import pandas; import matplotlib; from pandas.tools.plotting import scatter_matrix; data = pandas.read_csv("D://面积距离车站.csv",engine='python',encoding='utf-8') 显示文件大小 data.shape data 二.绘制多个变量两两之间的散点图:scatter_matrix()方法 #绘制多个变量两两之间的
详解python中的文件与目录操作 一 获得当前路径 1.代码1 >>>import os >>>print('Current directory is ',os.getcwd()) Current directory is D:/Python36 2.代码2 如果将上面的脚本写入到文件再运行 Current directory is E:/python/work 二 获得目录的内容 Python代码 >>> os.listdir (os.getcwd
介绍 Mybatis Generator(MBG)是Mybatis的一个代码生成工具.MBG解决了对数据库操作有最大影响的一些CRUD操作,很大程度上提升开发效率.如果需要联合查询仍然需要手写sql.相信很多人都听说过微服务,各个微服务之间是松耦合的.每个微服务仅关注于完成一件任务并很好地完成该任务.在一个微服务的开发过程中很可能只关注对单表的操作.所以MBG在开发过程中可以快速的生成代码提升开发效率. 本文将说到在springboot的项目中如何去配置(XML形式和Java配置类形式)和使用M
前言 最近一直被无尽的业务需求淹没,没时间喘息,终于接到一个能让我突破代码舒适区的活儿,解决它的过程非常曲折,一度让我怀疑人生,不过收获也很大,代码方面不明显,但感觉自己抹掉了 java.Tomcat.Spring 一直挡在我眼前的一层纱.对它们的理解上了一个新的层次. 好久没输出了,于是挑一个方面总结一下,希望在梳理过程中再了解一些其他的东西.由于 Java 繁荣的生态,下面每一个模块都有大量的文章专门讲述.所以我选了另外一个角度,从实际问题出发,将这些分散的知识串联起来,各位可以作为一个综述
由于工作的需求,在使用中,需要搭建负载均衡,研究了Apache+Tomat负载均衡的方案,并且通过检索相关的文章,进行了比较发现,Apache负载负载均衡在使用的效率上,远远不如Nginx的效率高,因此决定使用Nginx来进行服务的搭建.最初YUM安装了Nginx,但是不知道什么原因,Nginx的服务可以正常启动,静态页面也可以正常访问,但是就是无法正常的搭建虚拟主机和负载均衡.对引没有深究原因,决定把他卸载,然后手动安装. 手动安装好Nginx后,一切正常,虚拟主机,负载均衡的配置全部没有任何
前言 本文只为自己搭建过程中的一些简单的记录.如果实践中有疑问,可以一起探讨. 为了能在本机(macOS)模拟集群环境,使用了vb和docker-machine.整体持续集成的几个机器设施如下: 1.服务节点:三个manager节点,一个worker节点.manager需要占用更多的资源,manager配置尽量高一些.swarm的manager节点的容错率是 (N-1)/2 .N是manager节点数.也就是如果有3个manager,那就能容忍一个manager节点挂掉.官方的算法说明:Raft