spring 三:AOP及其实现

AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过 OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关 系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名 为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块 之间的耦合度,并有利于未来的可操作性和可维护性。

使用"横切"技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

AOP核心概念

1、横切关注点

对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。

2、切面(aspect)

是通知和切点的结合。通知和切点共同定义了切面的全部内容。

类是对物体特征的抽象,切面就是对横切关注点的抽象;业务流程运行的某个特定步骤,就是运行过程的关注点,关注点可能横切多个对象。

3、连接点(joinpoint)

连接点,程序执行过程中明确的点,如方法的调用或异常的抛出。Spring AOP中,连接点总是方法的调用,Spring并没有显式地使用连接点。是在应用执行过程中能够插入切面的一个点。

4、切入点(pointcut)

系列连接点的集合,它确定处理触发的时机。AOP框架允许开发者自己定义切入点,如使用正则表达式。切点定义了切面在何处要织入的一个或者多个连接点。

5、通知(advice)

所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。AOP框架在特定的连接点执行的动作。

通知定义了切面是什么以及何时使用的概念。

   Spring 切面可以应用5种类型的通知:

   前置通知(Before):在目标方法被调用之前调用通知功能。

   后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。

   返回通知(After-returning):在目标方法成功执行之后调用通知。

   异常通知(After-throwing):在目标方法抛出异常后调用通知。

   环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

6、目标对象

包含连接点的对象。也称为被处理对象或被代理对象。

7、织入(weave)

将切面应用到目标对象并导致代理对象创建的过程,是把切面应用到目标对象,并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。

在目标对象的生命周期中有多个点可以进行织入:

     编译期: 在目标类编译时,切面被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。

       类加载期:切面在目标加载到JVM时被织入。这种方式需要特殊的类加载器(class loader)它可以在目标类被引入应用之前增强该目标类的字节码。

        运行期: 切面在应用运行到某个时刻时被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。 SpringAOP就是以这种方式织入切面的。

8、引入(introduction)

添加方法或字段到被处理的类。Spring允许引入新的接口到任何被处理的对象。例如,可以使用一个引入,使任何对象实现IsModified接口,以此来简化缓存。引入允许我们向现有类添加新方法或属性。

9、AOP代理(proxy),AOP框架创建的对象,包含处理。简单地说,代理就是对目标对象的加强。Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理。前者为实现接口的目标对象的代理,后者为不实现接口的目标对象的代理。

例子:

bean包:

package com.ex.aop.target;


import org.springframework.stereotype.Component;

@Component
public class Target {
	public void mathodA() {
		System.out.println("Target的mathodA方法被调用了");
	}
	public void findAll() {
		System.out.println("Target的findAll方法被调用了");
	}
}
package com.ex.aop.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect//定义为一个切面
public class Advice {
	@Pointcut("execution(* com.ex.aop.target.*.*(..))")
	public void anyMethod() {
		
	}
	
	@Before("execution(* com.ex.aop.target.*.*(..))")//这个方法被定义为一个前置通知
	public void before() {
		System.out.println("Advice类的Before方法被调用了");
	}
	
	@After("execution(* com.ex.aop.target.*.find*(..))")//模糊匹配
	public void after() {
		System.out.println("after");
	}
	@AfterReturning(pointcut="anyMethod()")
	public void finaly() {
		System.out.println("finaly");
	}
	@Around("execution(* com.ex.aop.target.*.*(..))")//pointcut缩写形式
	public void around(ProceedingJoinPoint pjp) throws Throwable {//ProceedingJoinPoint类似一个拦截器
		System.out.println("aaaaaa");
		pjp.proceed();//执行目标对象的方法
		System.out.println("bbbbbbbbb");
	}
	@AfterThrowing(pointcut="execution(* com.ex.aop.target.*.*(..))",throwing="e")
	public void ex(Exception e) {
		System.out.println(e.getMessage());
		System.out.println("************");
	}
}

/s3/src/main/resources/applicationContext.xml 

<?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: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:annotation-config />
	<context:component-scan base-package="com.ex.aop.target" />	<!-- 扫描注解 -->
	<context:component-scan base-package="com.ex.aop.advice" />	<!-- 扫描注解 -->			
	<aop:aspectj-autoproxy/><!-- 对目标对象自动代理 -->
</beans>

test类:

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.ex.aop.target.Target;

public class Test {
	public static void main(String[] args) {
		ApplicationContext bean= new FileSystemXmlApplicationContext("/src/main/resources/applicationContext.xml");
		Target target=bean.getBean("target", Target.class);
		target.mathodA();
	}
}

AOP举例:

我们以系统中常用到的事务管控举例子。在系统操作数据库的过程中,不可避免地要考虑到事务相关的内容。如果在每一个方法中都新建一个事务管理器,那么无疑是对代码严重的耦合和侵入。为了简化我们的开发过程(实际上spring所做的一切实现都是为了简化开发过程),需要把事务相关的代码抽成出来做为一个独立的模块。通过AOP,确认每一个操作数据库方法为一个连接点,这些连接点组成了一个切面。当程序运行到其中某个一个切点时,我们将事务管理模块顺势织入对象中,通过通知功能,完成整个事务管控的实现。这样一来,所有的操作数据库的方法中不需要再单独关心事务管理的内容,只需要关注自身的业务代码的实现即可。所有的事务管控相关的内容都通过AOP的方式进行了实现。简化了代码的内容,将目标对象复杂的内容进行解耦,分离业务逻辑与横切关注点。

总结:AOP可以说是对OOP的补充和完善,通过代理模式实现。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码,属于静态代理

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值