spring-boot中的AOP
public class User {
private Integer id;
private String username;
private String note; public User(Integer id, String username, String note) {
this.id = id;
this.username = username;
this.note = note;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getNote() {
return note;
} public void setNote(String note) {
this.note = note;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", note='" + note + '\'' +
'}';
}
}
接口:
//@Component接口不用添加注入到容器,因为接口不能进行实例化
public interface UserService {
public void printUser(User user);
public void manyAspect();
}
实现类:
@Component
public class UserServiceImpl implements UserService { /**
* 这个方法将作为我们的AOP的接入点
* @param user
*/
@Override
public void printUser(User user) {
if (user.getUsername() == null){
throw new RuntimeException("检查用户参数是否为空。。。。");
}
System.out.println("id = "+ user.getId());
System.out.println("username = " + user.getUsername());
System.out.println("note = " + user.getNote());
} @Override
public void manyAspect() {
System.out.println("manyAspect------");
}
}
/**
* 定义切面
* @Aspect声明切面
*/
//@Aspect
public class MyAspect { //避免我们重复写一个表达式,引入了切入点概念PointCut,描述哪些类的哪些方法需要开启AOP编程。
@Pointcut("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.printUser(..))")
public void pointCut(){
} @Before("pointCut()")
public void before(){
System.out.println("before......");
} @After("pointCut()")
public void after(){
System.out.println("after......");
} @AfterReturning("pointCut()")
public void afterreturning(){
System.out.println("agterreturning.....");
} @AfterThrowing("pointCut()")
public void afterthrowing(){
System.out.println("afterthrowing.....");
} /**
* ProceedingJoinPoint类型参数,给参数的对象中有个方法proceed方法。回调原来的方法。
* @Around注解会取代原有目标的方法的通知。不进行回调得时候,方法是空的。
* @param joinPoint
* @throws Throwable
*/
@Around("pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around before....");
//可以在这里打断点去查看joinPoint的内容
joinPoint.proceed();
System.out.println("around after....");
}
/**
* http://localhost:8080/aop/userprint?id=22&username=quan¬e=huolala
* 有回调:
* around before...
* before......
* id = 22
* username = quan
* note = huolala
* agterreturning.....
* after......
* around after....
* ################
* 没回调:
* around before....
* around after....
*/ /**
* @DeclareParents作用:引入新的类来增强服务,
* value:指向你要增强功能的目标对象,这里要增强对象为UserServiceImpl对象
* defaultImpl:引入增强功能的类,UserValidatorImpl提供校验用户是否为空的
*/
@DeclareParents(value = "quan.springframework.springbootaop.aopdone.UserServiceImpl",defaultImpl = UserValidatorImpl.class)
public UserValidator userValidator; @DeclareParents(value = "quan.springframework.springbootaop.aopdone.UserServiceImpl",defaultImpl = UserValidatorIdImpl.class)
public UserValidatorId userValidatorId; /**
* 通知获取参数,
* && args(user)并将目标对象方法-名称为user的参数传递进来。
* @param joinPoint
* @param user
* 注意:
* JoinPoint类型的参数对于非环绕通知而言的参数。spring AOP自动传递到通知中
* 环绕通知自动你传递的参数为ProceedingJoinPoint类型的参数。
*/
@Before("pointCut() && args(user)")
public void beforeParam(JoinPoint joinPoint,User user){
Object[] args = joinPoint.getArgs();
System.out.println(args);
System.out.println("before param....");
} // @Before("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.printUser(..))")
// public void before(){
// System.out.println("before......");
// }
//
// @After("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.printUser(..))")
// public void after(){
// System.out.println("after......");
// }
//
// @AfterReturning("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.printUser(..))")
// public void afterreturning(){
// System.out.println("agterreturning.....");
// }
//
// @AfterThrowing("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.printUser(..))")
// public void afterthrowing(){
// System.out.println("afterthrowing.....");
// } /**
* execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.printUser(..))
* execution:表示执行时,拦截里面的正则匹配方法;
* *:表示任意返回类型的方法
* quan.springframework.springbootaop.aopdone.UserServiceImpl:指定目标对象的全限定类名
* printUser:指定目标对象的方法
* (**):表示任意参数进行匹配
*/ }
多切面:
/**
* 第一个切面
*/
@Order(3)
@Aspect
public class MyManyAop { @Pointcut("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.manyAspect(..))")
public void manyAspects(){
} @Before("manyAspects()")
public void before(){
System.out.println("MymanyAop1---before......");
} @After("manyAspects()")
public void after(){
System.out.println("MymanyAop1---after......");
} @AfterReturning("manyAspects()")
public void afterreturning(){
System.out.println("MymanyAop1---agterreturning.....");
} }
/**
* 第二个切面
*/
@Order(2)
@Aspect
public class MyManyAop2 { @Pointcut("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.manyAspect(..))")
public void manyAspects(){
} @Before("manyAspects()")
public void before(){
System.out.println("MymanyAop2---before......");
} @After("manyAspects()")
public void after(){
System.out.println("MymanyAop2---after......");
} @AfterReturning("manyAspects()")
public void afterreturning(){
System.out.println("MymanyAop2---agterreturning.....");
}
}
/**
* 第三个切面
*/
@Order(1)
@Aspect
public class MyManyAop3 { @Pointcut("execution(* quan.springframework.springbootaop.aopdone.UserServiceImpl.manyAspect(..))")
public void manyAspects(){
} @Before("manyAspects()")
public void before(){
System.out.println("MymanyAop3---before......");
} @After("manyAspects()")
public void after(){
System.out.println("MymanyAop3---after......");
} @AfterReturning("manyAspects()")
public void afterreturning(){
System.out.println("MymanyAop3---agterreturning.....");
}
}
各个切面需要加入到容器当中:
@Configuration
public class AopConfiguration { /**
* 需要将切面加入到容器当中才能被织入
* @return
*/
@Bean("myAspect")
public MyAspect initMyAspect(){
return new MyAspect();
} /**
* 第一个切面
*/
@Bean("myManyAop")
public MyManyAop initMyManyAspect1(){
return new MyManyAop();
} /**
* 第二个切面
*/
@Bean("myManyAop2")
public MyManyAop2 initMyManyAspect2(){
return new MyManyAop2();
} /**
* 第三个切面
*/
@Bean("myManyAop3")
public MyManyAop3 initMyManyAspect3(){
return new MyManyAop3();
} }
通过类增强的:
/**
* 新建一个增强接口
*/
public interface UserValidator { public boolean validate(User user);
} /**
* 增强接口实现类
*/
public class UserValidatorImpl implements UserValidator { @Override
public boolean validate(User user) {
System.out.println("add validate");
return user.getUsername() != null;
}
}
public interface UserValidatorId {
public boolean idBigTWY(User user);
} public class UserValidatorIdImpl implements UserValidatorId{ @Override
public boolean idBigTWY(User user) {
System.out.println("UserValidatorId");
return user.getId() > 20;
}
}
什么是织入:
/**
* 织入:生成动态代理对象并且将切面和目标对象方法编织称为约定流程的过程
* Spring推荐的方式是接口+实现类的模式。
* spring支持JDK和CGLIB;
* JDK要求被代理对象必须拥有接口。
* CGLIB不做要求
* spring处理规则:当需要使用AOP的类拥有接口时,会以JDK动态代理运行,否则已CGLIB运行
* 注意:
* Spring 5.x 中 AOP 默认依旧使用 JDK 动态代理。
* SpringBoot 2.x 开始,为了解决使用 JDK 动态代理可能导致的类型转化异常而默认使用 CGLIB。
*/
@Controller
@RequestMapping("/aop")
public class AopController { @Autowired
UserService userService; @RequestMapping("/userprint")
@ResponseBody
public User pringUser(Integer id,String username,String note){
User user = new User(id,username,note);
userService.printUser(user);
return user;
}
/**
* request:
*http://localhost:8080/aop/userprint?id=22&username=quan¬e=huolala
* result:
* before......
* id = 22
* username = quan
* note = huolala
* agterreturning.....
* after......
*/ @RequestMapping("/quote")
@ResponseBody
public User validateAndPrint(int id,String username,String note){
User user = new User(id,username,note);
//强制转换为UserValidator。
UserValidator userValidator = (UserValidator)userService;
if ( userValidator.validate(user) ){//判断是否为空user.username是否为空
userService.printUser(user);
} UserValidatorId userValidatorId = (UserValidatorId)userService;
if (userValidatorId.idBigTWY(user)){
System.out.println(user.getId());
}
return user;
} @RequestMapping("/many")
@ResponseBody
public String many(){
userService.manyAspect();
return "many aspect";
}
/**
* 顺序不一样的。
* MymanyAop1---before......
* MymanyAop2---before......
* MymanyAop3---before......
* manyAspect------
* MymanyAop3---agterreturning.....
* MymanyAop3---after......
* MymanyAop2---agterreturning.....
* MymanyAop2---after......
* MymanyAop1---agterreturning.....
* MymanyAop1---after......
*/ /**
* 加入Order:
* MymanyAop3---before......
* MymanyAop2---before......
* MymanyAop1---before......
* manyAspect------
* MymanyAop1---agterreturning.....
* MymanyAop1---after......
* MymanyAop2---agterreturning.....
* MymanyAop2---after......
* MymanyAop3---agterreturning.....
* MymanyAop3---after......
* 前置通知before都是从小到大运行,而后置通知和返回通知都是从大到小运行
* 典型的责任链模式顺序。
*/
}
spring-boot中的AOP的更多相关文章
- Spring Boot中使用AOP统一处理Web请求日志
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...
- Spring Boot中使用AOP记录请求日志
这周看别人写的springboot后端代码中有使用AOP记录请求日志,以前没接触过,因此学习下. 一.AOP简介 AOP为Aspect Oriented Programming的缩写,意为:面向切面编 ...
- 46. Spring Boot中使用AOP统一处理Web请求日志
在之前一系列的文章中都是提供了全部的代码,在之后的文章中就提供核心的代码进行讲解.有什么问题大家可以给我留言或者加我QQ,进行咨询. AOP为Aspect Oriented Programming的缩 ...
- 转:Spring Boot中使用AOP统一处理Web请求日志
在spring boot中,简单几步,使用spring AOP实现一个拦截器: 1.引入依赖: <dependency> <groupId>org.springframewor ...
- Spring boot中使用aop详解
版权声明:本文为博主武伟峰原创文章,转载请注明地址http://blog.csdn.net/tianyaleixiaowu. aop是spring的两大功能模块之一,功能非常强大,为解 ...
- (转)Spring Boot中使用AOP统一处理Web请求日志
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...
- Spring Boot中自定义注解+AOP实现主备库切换
摘要: 本篇文章的场景是做调度中心和监控中心时的需求,后端使用TDDL实现分表分库,需求:实现关键业务的查询监控,当用Mybatis查询数据时需要从主库切换到备库或者直接连到备库上查询,从而减小主库的 ...
- 56. spring boot中使用@Async实现异步调用【从零开始学Spring Boot】
什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执 ...
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题
Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只 ...
随机推荐
- 数据库delete from和truncate删除的区别详解
一:区别 1.delete from 后面可以直接接条件,truncate不可以 2.delete from 记录是一条条删除的,所删除的每行记录都会进入日志,而truncate一次性删除整个页,因此 ...
- vscode分栏显示快捷键
vscode没有默认的分栏快捷键,我们可以自定义,步骤如下: 1.Crtl + k,再Ctrl + s,调出快捷键设置面板 2.在搜索栏输入"视图:",在未定义快捷键的区域找到&q ...
- Windows系统散列值获取分析与防范
LM Hash && NTLM Hash Windows操作系统通常使用两种方法对用户的明文进行加密处理,在域环境中,用户信息存储在ntds.dit中,加密后为散列值.Windows操 ...
- 华为eNSP无限井号#解决方法
如下图所示,允许ensp相关应用通过防火墙
- bi工具是什么,如何选择?
商业智能使用的一套方法和技术根据解决方案的目的而广泛多样化.有些工具专注于数据准备方面,可能包括ETL(提取,转换,加载)层,以更好地组织和利用数据.有些工具专注于更广泛的企业使用,可能专注于数据混 ...
- 零售BI:为什么说零售行业非上一套企业BI系统不可?
如果你要问为什么现在越来越多的零售企业都会在公司上一套企业BI系统,这边文章就能解答你的疑惑. 2016年10月,马云在云栖大会上提出了"新零售"概念.在新零售时代,数字化转型打通 ...
- Vue框架简介和环境搭建
前言: 此篇随笔为个人学习前端框架Vue,js的技术笔记,主要记录一些自己在学习Vue框架的心得体会和技术总结,作为回顾和笔记使用. 这种写博客的方式,对刚开始学习Vue框架的我,也是一种激励,我相信 ...
- oj教程--向量容器
vector向量容器不但像数组一样对元素进行随机访问,还能在尾部插入元素,是一个简单.高效的容器, 完全可以替代数组.vector具有内存自动管理的功能,对于元素的插入和删除,可动态调整所占用的内存空 ...
- 让Node.js支持ES6的语法
使用命令,全局安装es-checker: cnpm install -g es-checker 安装好之后,执行以下命令来查看Node.js对ES6的支持情况. es-checker 可以从输出中查看 ...
- (第二章第二部分)TensorFlow框架之读取图片数据
系列博客链接: (第二章第一部分)TensorFlow框架之文件读取流程:https://www.cnblogs.com/kongweisi/p/11050302.html 本文概述: 目标 说明图片 ...