SSM学习—Spring(第六天学习记录)
程序员文章站
2022-06-06 13:59:22
...
Aop
- AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编程)的补充。
- AOP编程操作的主要对象是切面(aspect),而切面模块化横切关注点(可以把切面当做一个有特殊功能的类)
- 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应用在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的类里——这样的类我们通常称之为“切面”
专业名词
- 横切关注点
从每个方法中抽取出来的同一类非核心业务。(例如上图的日志) - 切面(Aspect)
封装横切关注点信息的类,每个关注点体现为一个通知方法。 - 通知(Advice)
切面必须要完成的各个具体工作 - 目标(Target)
被通知的对象 - 代理(Proxy)
向目标对象应用通知之后创建的代理对象 - 连接点(Joinpoint)
横切关注点在程序代码中的具体体现,对应程序执行的某个特定位置。例如:类某个方法调用前、调用后、方法捕获到异常后等。
在应用程序中可以使用横纵两个坐标来定位一个具体的连接点:
7. 切入点(pointcut):
定位连接点的方式。每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物。如果把连接点看作数据库中的记录,那么切入点就是查询条件——AOP可以通过切入点定位到特定的连接点。切点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
细节
切入点表达式:通过表达式去定位一个或多个具体的连接
语法格式:execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]))
当前连接点所在方法的方法名、当前传入的参数值等等。这些信息都封装在JoinPoint接口的实例对象中
@Component //先标示为组件,交给IOC容器管理
@Aspect //标识为切面
@Order(2)
public class LoggingAspect {
/**
* 前置通知:在目标方法执行之前执行的方法
* 注意导包的时候不要导错了
* 切入点表达式
* execution(public int Aspectj.Before.ArithmeticCalculatorimpl.add(int,int))
*声明切入点表达式
*/
@Pointcut("execution(* Aspectj.Before.*.*(..))")
public void declarePointCut(){
}
// @Before("execution(public int Aspectj.Before.ArithmeticCalculatorimpl.add(int,int))")
@Before("declarePointCut()")
public void beforeMethod(JoinPoint joinPoint){
Object args[]=joinPoint.getArgs();
System.out.println("前置通知:"+ Arrays.asList(args));
}
/**
* 后置通知:在目标方法之后执行,不管目标方法有没有抛出异常
* * * com.atguigu.spring.aspectJ.annotation.*.*(..)
* * : 任意修饰符 任意返回值
* * : 任意类
* * : 任意方法
* ..: 任意参数列表
*
*/
@After("execution(* Aspectj.Before.*.*(..))")
public void AfterMethod(JoinPoint joinPoint){
//方法的名字
String methodName=joinPoint.getSignature().getName();
System.out.println("后置通知:"+methodName);
}
/**
* 返回通知:在目标方法正常执行结束之后执行,可以获取方法的返回值
* 通过returning来制定一个名字,必须与方法里的形参一样
*/
@AfterReturning(value="execution(* Aspectj.Before.*.*(..))",returning = "result")
public void AfterReturnMethod(JoinPoint joinPoint,Object result){
//方法的名字
String methodName=joinPoint.getSignature().getName();
System.out.println("返回通知:"+methodName+"返回结果"+result);
}
@AfterThrowing(value = "execution(* Aspectj.Before.*.*(..))",throwing = "ex")
public void AfterThrowMethod(JoinPoint joinPoint,Exception ex){
//方法的名字
String methodName=joinPoint.getSignature().getName();
System.out.println("异常通知:"+ex);
}
/**
* 环绕通知:环绕着目标方法执行,可以理解为前置,后置,返回,异常的结合体更像是动态代理的过程
*/
@Around(value = "execution(* Aspectj.Before.*.*(..))")
public Object AroundMethod(ProceedingJoinPoint joinPoint){
//执行目标放阿飞
try {
//前置
Object obj=joinPoint.proceed();
return obj;
//返回
}catch (Throwable e){
e.printStackTrace();
}finally {
//后置
}
return null;
}
}
Aspectj(Java社区里最完整的AOP框架)
所需jar包
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-5.2.0.RELEASE.jar
spring-aspects-5.2.0.RELEASE.jar
命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
重用切入点定义
1)在编写AspectJ切面时,可以直接在通知注解中书写切入点表达式。但同一个切点表达式可能会在多个通知中重复出现。
2)在AspectJ切面中,可以通过@Pointcut注解将一个切入点声明成简单的方法。切入点的方法体通常是空的,因为将切入点定义与应用程序逻辑混在一起是不合理的。
3)切入点方法的访问控制符同时也控制着这个切入点的可见性。如果切入点要在多个切面*用,最好将它们集中在一个公共的类中。在这种情况下,它们必须被声明为public。在引入这个切入点时,必须将类名也包括在内。如果类没有与这个切面放在同一个包中,还必须包含包名。
4)其他通知可以通过方法名称引入该切入点
代码实现:
@Pointcut("execution(* Aspectj.Before.*.*(..))")
public void declarePointCut(){
}
// @Before("execution(public int Aspectj.Before.ArithmeticCalculatorimpl.add(int,int))")
@Before("declarePointCut()")
在不同的文件里面调用
//@Before("execution(* Aspectj.Before.*.*(..))")
@Before("Aspectj.Before.LoggingAspect.declarePointCut()")
指定切面优先级
1)在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。
2)切面的优先级可以通过实现Ordered接口或利用@Order注解指定。
3)实现Ordered接口,getOrder()方法的返回值越小,优先级越高。
@Component
@Aspect
@Order(1) //设置切面优先级,int类型的值,2147483647
下一篇: PHP小bug汇总[持续更新]