Spring切面简记及应用(spring aop)
来源:互联网 发布:伊辛模型c语言代码 编辑:程序博客网 时间:2024/05/17 16:57
概念
面向切面编程:把逻辑代码和处理琐碎事务的代码分离开,以便能够分离复杂度。
切面(AOP)术语
1.连接点(Joinpoint)
2.切点(Pointcut)
3.增强(Advice)
Before advice
After returning advice
After throwing advice
After(finally) advice
Around advice
4.目标对象(Target)
5.引入(Introduction)
6.织入(Weaving)
7.代理(Proxy)
8.切面(Aspect)
优点
更清晰的代码逻辑,业务逻辑只关注自己本身,不用去管琐碎的事情,比如:安全,日志,事务等等。
可以减少代码量
更清晰的代码逻辑,业务逻辑只关注自己本身,不用去管琐碎的事情,比如:安全,日志,事务等等。
可以减少代码量
想了解概念的同学可以去百度或者先看下面的demo 再理解
应用
maven依赖
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.6</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.6</version></dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.6</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.6</version></dependency>
这里我只提供切面需要的依赖
如果不懂maven的同学 可以先看本站的教程
准备工作
// 接口public interface IUserDao {void save(Person person);}@Component // 加入容器public class UserDao implements IUserDao{@Overridepublic void save(Person person) {System.out.println("-----核心业务:保存!!!------"); }}public class Person {private String name;private String sex;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}}
// 接口public interface IUserDao {void save(Person person);}@Component // 加入容器public class UserDao implements IUserDao{@Overridepublic void save(Person person) {System.out.println("-----核心业务:保存!!!------"); }}public class Person {private String name;private String sex;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}}
切面配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启注解扫描 --><context:component-scan base-package="net.begincode.aop_anno"></context:component-scan><!-- 开启动态代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/></beans>
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启注解扫描 --><context:component-scan base-package="net.begincode.aop_anno"></context:component-scan><!-- 开启动态代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/></beans>
指定切面
@Component@Aspect // 指定当前类为切面类public class Aop {// 指定切入点表达式: 拦截哪些方法; 即为哪些类生成代理对象@Pointcut("execution(* net.begincode.aop_anno.*.*(..))")public void pointCut_(){}// 前置通知 : 在执行目标方法之前执行@Before("pointCut_()")public void begin(){System.out.println("开始事务/异常");}// 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】@After("pointCut_()")public void after(){System.out.println("提交事务/关闭");}// 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】@AfterReturning("pointCut_()")public void afterReturning() {System.out.println("afterReturning()");}// 异常通知: 当目标方法执行异常时候执行此关注点代码@AfterThrowing("pointCut_()")public void afterThrowing(){System.out.println("afterThrowing()");}// 环绕通知:环绕目标方式执行@Around("pointCut_()")public void around(ProceedingJoinPoint pjp) throws Throwable{Object[] objs = pjp.getArgs();Person p = (Person) objs[0];System.out.println(p.getName());System.out.println("环绕前....");pjp.proceed(); // 执行目标方法System.out.println("环绕后....");}}
@Component@Aspect // 指定当前类为切面类public class Aop {// 指定切入点表达式: 拦截哪些方法; 即为哪些类生成代理对象@Pointcut("execution(* net.begincode.aop_anno.*.*(..))")public void pointCut_(){}// 前置通知 : 在执行目标方法之前执行@Before("pointCut_()")public void begin(){System.out.println("开始事务/异常");}// 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】@After("pointCut_()")public void after(){System.out.println("提交事务/关闭");}// 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】@AfterReturning("pointCut_()")public void afterReturning() {System.out.println("afterReturning()");}// 异常通知: 当目标方法执行异常时候执行此关注点代码@AfterThrowing("pointCut_()")public void afterThrowing(){System.out.println("afterThrowing()");}// 环绕通知:环绕目标方式执行@Around("pointCut_()")public void around(ProceedingJoinPoint pjp) throws Throwable{Object[] objs = pjp.getArgs();Person p = (Person) objs[0];System.out.println(p.getName());System.out.println("环绕前....");pjp.proceed(); // 执行目标方法System.out.println("环绕后....");}}
使用junit测试
ApplicationContext ac = new ClassPathXmlApplicationContext("net/begincode/aop_anno/bean.xml");@Testpublic void testApp() {IUserDao userDao = (IUserDao) ac.getBean("userDao");System.out.println(userDao.getClass());//$Proxy001 Person person = new Person();person.setName("abc");person.setSex("man");userDao.save(person);}
ApplicationContext ac = new ClassPathXmlApplicationContext("net/begincode/aop_anno/bean.xml");@Testpublic void testApp() {IUserDao userDao = (IUserDao) ac.getBean("userDao");System.out.println(userDao.getClass());//$Proxy001 Person person = new Person();person.setName("abc");person.setSex("man");userDao.save(person);}
输出:
class com.sun.proxy.$Proxy15abc环绕前....开始事务/异常-----核心业务:保存!!!------环绕后....提交事务/关闭afterReturning()
如果目标对象有实现接口,spring会自动选择"JDK代理"
如果目标对象没有实现接口,spring就会使用"cglib"代理
AOP的应用很广泛 功能很强大 可以做:安全,日志,事务等等。
这里介绍的只是最基本使用方法
参考文献:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
具体应用
在begincode 问答系统中 我们利用切面去拦截controller,使指定的入参被拦截
@Aspect@Componentpublic class RequestAspect { @Pointcut("execution(* net.begincode.controller.*.*(..))") public void pointCut_() { } @Around("pointCut_()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object[] objects = proceedingJoinPoint.getArgs(); for (int i = 0; i < objects.length; i++) { if (objects[i] instanceof ProblemLabelParam) { ProblemLabelParam problemLabelParam = (ProblemLabelParam) objects[i]; problemLabelParam.check(); } } return proceedingJoinPoint.proceed(); }}
拦截所有从controller进去的参数 并且验证有没有 ProblemLabelParam 类型的参数
如果有的话,则调用其中的check方法验证传入的参数是否有异常
部分代码如下:
public class ProblemLabelParam extends Param{ .... @Override public void check() { checkNotEmpty(problem.getContent(),ProblemResponseEnum.PROBLEM_ADD_ERROR); checkNotEmpty(problem.getTitle(),ProblemResponseEnum.PROBLEM_ADD_ERROR); } .... }
我们规定入参对象必须全部继承Param类 不能使用原有的model直接进入方法
并且实现抽象的check方法
public abstract class Param { public abstract void check(); public void checkNotNull(Object value, ResponseEnum status) { checkArgs(value != null, status); } public void checkNotEmpty(String value, ResponseEnum status) { checkArgs(StringUtils.isNotBlank(value), status); } public void checkArgs(boolean success, ResponseEnum status) { if (!success) { throw new BizException(status); } }}
- Spring切面简记及应用(spring aop)
- spring的aop切面的简单应用
- Spring aop切面实际应用 XML配置
- Spring aop切面实际应用 XML配置
- 【Spring】AOP - 面向切面
- spring aop 定义切面
- Spring AOP切面
- 【Spring】AOP - 面向切面
- Spring AOP切面编程
- spring Aop切面
- spring-Aop切面编程
- Spring的切面 AOP
- spring AOP切面使用
- Spring AOP自定义切面
- Spring AOP面向切面
- 切面优先级 Spring Aop
- spring aop 切面测试
- Spring AOP 切面编程
- 2048
- drawerLayout
- ckeditor中 config.js等通过ckeditor.js引入文件手动修改方法
- 世界因大数据而 改变
- leetcode-232-Implement Queue using Stacks
- Spring切面简记及应用(spring aop)
- redis--keys命令
- A+B Problem(V)
- jQuery插件:Validation中success和submitHandler两个方法的区别
- 基因(Gene) 数据库 (Database) 和 软件 (Software)
- 最长回文子序列(LPS)
- 1031. Hello World for U (20)
- 关于 thinkPHP 项目分组后的访问问题
- 内容提供者及内容解析者的实现步骤