首页 > 学院 > 开发设计 > 正文

Spring切面简记及应用(spring aop)

2019-11-08 02:33:29
字体:
来源:转载
供稿:网友

概念

面向切面编程:把逻辑代码和处理琐碎事务的代码分离开,以便能够分离复杂度。

切面(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>

这里我只提供切面需要的依赖

如果不懂maven的同学 可以先看本站的教程

准备工作

// 接口public interface IUserDao {	void save(Person person);}@Component   // 加入容器public class UserDao implements IUserDao{	@Override	public 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>

指定切面

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

输出:

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表