框架——AOP(详解)

AOP(Aspect Oriented Programming,面向切面编程):

在程序原有的纵向执行流程中,针对某一个点或者一些方法(每一个方法都是连接点的意思)添加通知,形成横切面;

  • AOP是继OOP(Object Oriented Programming,面向对象编程)之后的又一影响巨大的技术;
  • AOP是一种设计思想,实际上是对OOP的升级,是对OOP的补充,而不是替代!经常和OOP一起使用;
  • OOP的核心单位是类,AOP则是切面;
  • 典型的例子包括日志、验证、事务管理等;

简单的来说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们已有的方法进行增强

优点:

减少重复代码,提高开发效率,方便维护

 

术语:

关注点:一个关注点可以是一个特定的问题

连接点:Joinpoint 连接点是类中的方法

切入点:Pointcut 切入点是被抽取了共性功能的方法(指引通知切入连接点的一个地址)

通知(方法):Advice 被抽取的共性功能的代码逻辑(方法)

引入:Introduction 通知只能抽取逻辑代码,变量是拿不出来的,把变量引入到切入点方法

目标对象:Target Object 有切入点方法的对象(就像明星)

代理对象:AopProxy Spring 代理目标对象就叫aop代理(就像经纪人)

织入:Weaving 代理对象吧通知织入到目标对象的切入点方法中,是一个动作,一个过程

切面:Aspect 通知和切入点之间的关系

 

@Transactional实现事务管理

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
     <property name="dataSource" ref="dataSource"/>
</bean>    
<tx:annotation-driven transaction-manager="txManager"/> //开启事务注解

 

AOP的原理:动态代理(通知方法就像代理对象为目标对象额外实现的方法

Aop两种代理模式:

jdk的动态代理 和 CGLIB实现机制

jdk的动态代理:前提是,被代理的对象必须要有实现接口!(基于接口)

使用的JDK的java.lang.reflect(反射).Proxy(代理)类的newProxyInstance方法实现动态代理,对目标对象的方法进行功能追加;

newProxyInstance的三个参数

  1. loader:类加载器,获得目标对象的类加载器(写法://得到字节码对象//对象.getclass().getclassloader(),写法固定)
  2. interfaces:得到目标对象的所有实现接口的 字节码对象(每个类被加载之后,系统就会为该类生成一个对应的字节码对象,通过该字节码对象就可以访问到JVM中的对应的类)的 数组(多个对象)(写法:对象.getclass().getInterfaces(),写法固定)
  3. 需要一个实现了InvocationHandler接口的对象,需要自己手动完成,增强在这完成

newProxyInstance返回一个代理对象

 

五大通知实现的接口:

前置通知(Before advice)MethodBeforeAdvice: 在某连接点之前执行的通知

后置通知(After returning advice) AfterReturningAdvice: 在某连接点正常完成后执行的通知

异常通知(After throwing advice) ThrowsAdvice: 在方法抛出异常退出时执行的通知

最终通知(After finally advice): 当某连接点退出的时候执行的通知(不管是否有异常)

环绕通知(Around advice) MethodInterceptor: 包围一个连接点的通知,这是最强大的一种通知类型

 

CGLIB实现机制:

 

  • 配置包扫描器,把目标类和切面类纳入到spring容器中管理

<context:component-scan base-package="com.cj.study.spring.aop.annotation" />

  • 启动aop的注解解析器

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  • 切面类

@Aspect

  • 切入点和切入点表达式

 

@Pointcut("execution(* 完全限定名.*.*(..))")

public void aaa(){}

  • 切面里的通知方法

@Before("aaa()")

 

XML文件方式实现AOP

<!--目标实现类-->
<bean id="calculateImpl" class="com.xxx.aspectj.xml.CalculateImpl"></bean>
<!--切面实现类-->
 	<bean id="aspects" class="com.xxx.aspectj.xml.MyAspect" />
 	<!-- 配置切面 -->
 	<aop:config>
 		<aop:pointcut expression="" id=""/>
 		<aop:aspect id="aspect" ref="aspects">
 			
 			<aop:pointcut expression="execution(* com.xxx.aspectj.xml.CalculateImpl.add(..)) " id="pointcut"/>
 			<aop:around method="five" pointcut-ref="pointcut" />
 			<aop:before method="one" pointcut-ref="pointcut" /> 
 			<aop:after-returning method="two"  pointcut-ref="pointcut"  returning="re"/>
 						
 			<!--  			
 			<aop:after-throwing method="three" pointcut-ref="pointcut"  throwing="ex"/>
 			<aop:after method="four" pointcut-ref="pointcut"  />  -->
 			
 	   </aop:aspect>
 	</aop:config>

MyAspect类

public class MyAspect {
	//在Java文件中选择类名,然后Copy Qualified Name;
	//怎样访问当前连接点的细节
	public void one(JoinPoint jp){
		String name = jp.getSignature().getName();
		Object[] args = jp.getArgs();
		System.out.println(name+"前置通知执行"+",参数列表是"+Arrays.asList(args));
	}
	public void two(JoinPoint jp,Object re){
		
		String name = jp.getSignature().getName();
		System.out.println("后置通知执行的返回结果是"+re);
	}
	public void three(JoinPoint jp,Exception ex){
		System.out.println("异常通知执行的异常信息为"+ex);
	}
	public void four(){
		System.out.println("最终通知执行");
	}
	public Object five(ProceedingJoinPoint pjp){
		Object[] args = pjp.getArgs();
		String name = pjp.getSignature().getName();
		Object result=null;
		try {
			System.out.println(name+"环绕准备就绪,参数列表是:"+Arrays.asList(args));
			System.out.println("前置通知执行");
			result = pjp.proceed();
			System.out.println(name+"的返回结果是:"+result);
			System.out.println("后置通知执行");
		} catch (Throwable e) {
			
			e.printStackTrace();
			System.out.println("异常通知执行");
		}finally{
			System.out.println(name+"环绕执行完毕,参数列表是:"+Arrays.asList(args));
			System.out.println("最终通知执行");
		}				
		return result;		
	}
}

注解方式实现AOP

<!-- spring不自动寻找带注解的类,需要告诉哪些包中存在带注解的类 -->
 	<context:component-scan base-package="com.xxx.aspectj.annotation"></context:component-scan>
 	<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>

MyAspect类

@Component
@Aspect


//通过@Order(*)标注指定切面优先级,*整数数值越小,优先级越高
public class MyAspect {
	//定义切点
	@Pointcut("execution(* com.xxx.aspectj.annotation.CalculateImpl.*(..))")
	public void pointcut(){
		
	}
	@Before("pointcut()")
	public void c(JoinPoint jp){
		String name = jp.getSignature().getName();
		Object[] args = jp.getArgs();
		System.out.println(name+"前置通知1执行"+",参数列表是"+Arrays.asList(args));
	}
	@Before("execution(* com.xxx.aspectj.annotation.CalculateImpl.*(..))")
	public void b(JoinPoint jp){
		String name = jp.getSignature().getName();
		Object[] args = jp.getArgs();
		System.out.println(name+"前置通知2执行"+",参数列表是"+Arrays.asList(args));
	}
	/*@After("execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))")
	public void four(){
		System.out.println("最终通知执行");
	}*/
	@AfterReturning(pointcut="execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))",returning="re")
	public void two(JoinPoint jp,Object re){
		
		String name = jp.getSignature().getName();
		System.out.println(name+"后置通知执行的返回结果是"+re);
	}
	@AfterThrowing(pointcut="execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))",throwing="ex")
	public void three(JoinPoint jp,Exception ex){
		System.out.println("异常通知执行的异常信息为"+ex);
	}
	
	/*@Around("execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))")
	public Object five(ProceedingJoinPoint pjp){
		Object[] args = pjp.getArgs();
		String name = pjp.getSignature().getName();
		System.out.println(name+"环绕前置就绪,参数列表是:"+Arrays.asList(args));
		Object result=null;
		try {
			result = pjp.proceed();
			System.out.println(name+"的环绕返回结果是:"+result);
		} catch (Throwable e) {
			
			e.printStackTrace();
			System.out.println("异常通知执行");
		}finally{
			System.out.println(name+"环绕后置执行完毕,参数列表是:"+Arrays.asList(args));
		}
		
		
		return result;
		
	}*/
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值