Spring之AOP初体验

记录笔记

面向切面编程AOP

它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块 。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可 维护性。
如一些模块要进行日志操作,这属于不同模块中相同的逻辑操作,就可以用aop的方式,给这个模块横切一刀形成一个切面。然后将我们的操作操作织入到对应的方法当中。

相关概念

  • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。(切点+通知)
  • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。(可以被增强的方法,Joint point 是所有可能被织入 Advice 的候选的点)
  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。定义了增强的方法。
  • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
  • Target(目标对象):织入 Advice 的目标对象.。
  • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object

通知的类型

  • 前置通知(@Before) , 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)
  • 后置通知(@After), 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
  • 返回通知(@AfterReturning), 在一个 join point 正常返回后执行的 advice
  • 异常通知(@AfterThrowing), 当一个 join point 抛出异常后执行的 advice
  • 环绕通知(@Around), 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.

工程搭建

导入相关依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
        <dependency>
            <!-- 引入切面 相关依赖-->
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.4</version>
        </dependency>
    </dependencies>

只需要3个步骤

  • 1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
    2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
    3)、开启基于注解的aop模式;@EnableAspectJAutoProxy

第一步定义通知(Advice)并且指定切点(Point-cut)

使用@Aspect标识这是一个切面类。(后面会将它加入到容器中),并且标识了切点,也就是需要加强通知的方法,用表达式(public int com.kuake.aop.Machine.*(..),Machine下的所有方法

@Aspect
public class LogAdvice {
	@Pointcut(value="execution(public int com.kuake.aop.Machine.*(..))")
	public void pointcut(){
	}
	
	@Before(value = "pointcut()")
	public void logBefore(){
		System.out.println("logBefore....");
	}
	
	@After(value = "pointcut()")
	public void logAfter(JoinPoint joinPoint){
		System.out.println(joinPoint.getSignature().getName()+"logAfter....");
	}
	
	@AfterReturning(value="pointcut()",returning="result")
	public void logReturn(Object result){
		System.out.println("logReturn....返回值"+result);
	}
	
	@AfterThrowing(value="pointcut()",throwing="exception")
	public void logException(JoinPoint joinPoint,Exception exception){
		System.out.println(joinPoint.getSignature().getName()+"logException...."+exception);
	}
	
	@Around(value="pointcut()")
	public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable{
		System.out.println("logAround....");
//		System.out.println("logAround....proceedbefore...");
		// 这个就是方法的返回值
		Object proceed = joinPoint.proceed();
        System.out.println("logAround....");
//		System.out.println("logAround....proceedafter...改变返回值为2");
		return proceed;
	}
}

定义目标类target

这个类中的div方法也就是我们加强了的方法

public class Machine {
	public int  div(int i,int j){
		System.out.println("MathCalculator...div...");
		return i/j;
	}
}

将组件加入到容器当中,并且开始基于注解的aop

@EnableAspectJAutoProxy
@Configuration
public class MyConfigAop {

    //将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)需要交给spring管理
	@Bean
	public Machine machine(){
		return new Machine();
	}
	@Bean
	public LogAdvice logAdvice(){
		return new LogAdvice();
	}
}

进行测试

public class IOCTest_AOP {
    /**
     * 测试AOP的方法
     */
	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigAop.class);
		
		Machine machine = applicationContext.getBean(Machine.class);

        System.out.println(machine);
		machine.div(1, 1);
		
		applicationContext.close();
	}

}
logAround....
logBefore....
MathCalculator...div...
logAround....
divlogAfter....
logReturn....返回值1

执行过程如下:
在这里插入图片描述

发布了98 篇原创文章 · 获赞 44 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43732955/article/details/98986280