JavaSpring 第三章Aop

本章内容

Aop简介
基于XML实现Aop
基于注解实现Aop
1.Aop简介
1.1Aop相关概念

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
(翻译成:面向方面编程 也许更加贴切)它是一种在原有功能的基础上(无需改变原有编码),额外加入某一方面功能(处理)的技术。
核心是通过代理对象代替原有对象,从而拦截原有对象功能(方法)的执行,从而增加额外的功能。也就是增强原有的功能。所以添加的功能所在的类经常叫做增强类。由于这种功能的执行有时间和位置的规则(很像事件处理),有时候增强类也叫通知类。不要被名字所混淆。

1.2Aop原理

将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决,采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能
Aop编程很像我们曾经的过滤器,我们的过滤器是不是为所有servlet加入了登陆验证的功能,过滤器Filter的应用就是一种Aop思想的实现。

1.3Aop的相关术语

增强处理(Advice)

​ 前置增强、后置增强、环绕增强、异常抛出增强、最终增强等类型

切入点(Pointcut)

连接点(Join Point)

切面(Aspect)

目标对象(Target object)

AOP代理(AOP proxy)

织入(Weaving)

增强(Adivce):又翻译成通知,定义了切面是什么以及何时使用,描述了切面要完成的工作和何时需要执行这个工作。是织入到目标类连接点上的一段程序代码。增强包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方位信息。(所以spring提供的增强接口都是带方位名:BeforeAdvice、(表示方法调用前的位置)AfterReturninAdvice、(表示访问返回后的位置)ThrowAdvice等等,所以只有结合切点和增强两者一起才能确定特定的连接点并实施增强逻辑)

切入点(Pointcut):Advice定义了切面要发生“故事”和时间,那么切入点就定义了“故事”发生的地点。例如某个类或者方法名,Spring中允许我们使用正则来指定。像查询条件。

连接点(Joinpoint):切入点匹配的执行点称作连接点。如果说切入点是查询条件,那连接点就是被选中的具体的查询结果。程序执行的某个特定位置,程序能够应用增强代码的一个“时机”,比如方法调用或者特定异常抛出,像满足条件的查询结果

切面(Aspect):切点和增强组成切面。它包括了横切逻辑的定义,也包括了连接点的定义。Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中(满足了条件的新增功能)

代理(Proxy):AOP框架创建的对象。一个类被AOP织入增强之后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类。

目标对象(Target):增强逻辑的织入的目标类 原类

织入(Weaving):将增强添加到目标类具体连接点上的过程。AOP有三种织入的方式:编译期织入、类装载期织入、动态代理织入(spring采用动态代理织入)

2.Aop的实现步骤(基于XML)
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   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/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--需要aop的命名空间-->
 略......
</beans>
2.1编写增强类或叫做通知类(增强代码放的类)
public class MyAdvice  {
	public void zhiXingQian (JoinPoint joinPoint ){
        System.out.println("前置通知");
    }
    public void fanHuiHou(JoinPoint joinPoint,Object returnVal){
        System.out.println("返回通知-->返回值:"+returnVal);
    }

    public Object huanRao(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知前");       
        Object object= joinPoint.proceed();
        System.out.println("环绕通知后");
        return object;
    }

    public void yiChangHou(JoinPoint joinPoint,Throwable throwable){
        System.out.println("异常通知:"+ throwable.getMessage());
    }

    public void zhiXingHou(JoinPoint joinPoint){
        System.out.println("后置通知");
    }
}

输出信息带类名方法名版本:

 /*目标对象类名joinPoint.getTarget().getClass().getName()
目标对象执行的方法的 方法名  joinPoint.getSignature().getName()方法名*/
public class MyAdvice  {
	public void zhiXingQian (JoinPoint joinPoint ){
		String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+"执行前====前置通知");
    }

    public void fanHuiHou(JoinPoint joinPoint,Object returnVal){
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+" 返回通知-->返回值:"+returnVal);
    }

    public Object huanRao(ProceedingJoinPoint joinPoint) throws Throwable {
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
		
        System.out.println(exeName+"执行前,环绕通知");       
        Object object= joinPoint.proceed();//目标的方法执行
        System.out.println(exeName+"执行后,环绕通知");
        return object;
    }

    public void yiChangHou(JoinPoint joinPoint,Throwable throwable){
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+"执行发生异常,异常通知:"+ throwable.getMessage());
    }

    public void zhiXingHou(JoinPoint joinPoint){
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+"执行之后,后置通知");
    }
}

2)容器配置文件 启用aop

<!--启用aop-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3)配置aop

<!--1.增强类 或者叫通知 -->
	<bean id="myadvice" class="com.springstudy.MyAdvice"></bean>
	<!-- 配置AOP 切面 -->
	<aop:config>
		<!--定义切点,条件 在哪执行增强 -->
		<aop:pointcut id="pointcut"
			expression="execution(*   com.springstudy.springfirst.print.impl.*.*(..))"></aop:pointcut>
		<aop:aspect ref="myadvice">
		    <!-- 前置通知 -->
			<aop:before method="zhiXingQian" pointcut-ref="pointcut" />
			<!-- 返回通知 returning="returnVal" 定义返回值 必须与类中声明的名称一样 -->
			<aop:after-returning method="fanHuiHou"
				pointcut-ref="pointcut" returning="returnVal" />
			<!-- 环绕通知 -->
			<aop:around method="huanRao" pointcut-ref="pointcut" />
			<!--异常通知 throwing="throwable" 指定异常通知错误信息变量,必须与类中声明的名称一样 -->
			<aop:after-throwing method="yiChangHou"
				pointcut-ref="pointcut" throwing="throwable" />
			<!-- 后置通知 -->
			<aop:after method="zhiXingHou" pointcut-ref="pointcut" />
		</aop:aspect>
	</aop:config>

4)原有代码不变,执行看结果

关于切点表达式:

execution:执行
*com.springstudy.springfirst.print.impl.*.*(…)
任意返回值类型com.springstudy.springfirst.print.impl包下任意类的任意方法(任意参数)
*com.springstudy.springfirst.print…*.*(…)
任意返回值类型com.springstudy.springfirst.print包及任意子包下任意类的任意方法(任意参数)
3.Aop基于注解

3.1编写增强类并使用相应注解

@Component
@Aspect
@EnableAspectJAutoProxy //开启aop,容器中有一个类有就可以(通常应该在配置类)或者xml中<aop:aspectj-autoproxy/>
public class MyAdvice  {
	//定义切点
    @Pointcut("execution (* com.springstudy.springfirst.print.impl.*.*(..))")
    public void pct() {}//这个空方法 方法名()作为 切点的id
    
    @Before("pct()")
	public void zhiXingQian (JoinPoint joinPoint ){
		String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+"执行前====前置通知");
    }
    
    @AfterReturning(pointcut="pct()",returning="returnVal")
    public void fanHuiHou(JoinPoint joinPoint,Object returnVal){
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+" 返回通知-->返回值:"+returnVal);
    }
    @Around("pct()")
    public Object huanRao(ProceedingJoinPoint joinPoint) throws Throwable {
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名 
        System.out.println(exeName+"执行前,环绕通知");       
        Object object= joinPoint.proceed();//目标的方法 原有的功能代码 执行
        System.out.println(exeName+"执行后,环绕通知");
        return object;
    }
    @AfterThrowing(pointcut = "pct()",throwing = "throwable")
    public void yiChangHou(JoinPoint joinPoint,Throwable throwable){
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+"执行发生异常,异常通知:"+ throwable.getMessage());
    }
    @After("pct()")
    public void zhiXingHou(JoinPoint joinPoint){
    	String tarClassName = joinPoint.getTarget().getClass().getName();//得到类名
		String methodName = joinPoint.getSignature().getName();//得到方法名
		String exeName = tarClassName+"."+methodName;//得到执行目标的 类名.方法名
        System.out.println(exeName+"执行之后,后置通知");
    }
}

3.2配置自动扫描,加入增强类(通知类Advice所在的包),多个包以 , 分隔

<context:component-scan base-package="com.springstudy"></context:component-scan>

xeName = tarClassName+“.”+methodName;//得到执行目标的 类名.方法名
System.out.println(exeName+“执行之后,后置通知”);
}
}


3.2配置自动扫描,加入增强类(通知类Advice所在的包),多个包以   ,   分隔

```xml
<context:component-scan base-package="com.springstudy"></context:component-scan>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值