AOP:Aspect-Oriented Programming。AOP是OOP的补充,是GOF的延续。我们知道设计模式是对于面向对象设计中经验的总结,它孜孜不断追求的就是调用者与被调用者之间的解耦。有了设计模式我们可以更有效的利用面向对象的特性,使得整个软件设计更加灵活、优雅。但是设计模式是基于面向对象的思想而形成的,更多的时候关注的是对象层次的东西,在解决对象行为内部问题方面却有些不足。AOP的出现恰恰就是对面向对象思想做出了完美的补充。
说到AOP,我们就不得不来提一下软件的纵向和横向问题。从纵向结构来看就是我们软件系统的各个模块,它主要负责处理我们的核心业务(例如商品订购、购物车查看);而从横向结构来看,我们几乎每个系统又包含一些公共模块(例如权限、日志模块等)。这些公共模块分布于我们各个核心业务之中(例如订购和查看商品明细的过程都需要检查用户权限、记录系统日志等)。这样一来不仅在开发过程中要处处关注公共模块的处理而且开发后维护起来也是十分麻烦。而有了AOP之后将应用程序中的商业逻辑同对其提供支持的通用服务进行分离,使得开发人员可以更多的关注核心业务开发。
AOP的主要应用场景
AOP在系统开发中应用非常广泛,常见场景如下:
- 事务处理
- 日志处理
- 异常处理
- 权限控制
- 系统性能监控
- 其他
AOP的核心概念
1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)
对连接点进行拦截的定义
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
Spring对AOP的支持
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:
- 1、定义普通业务组件
- 2、定义切入点,一个切入点可能横切多个业务组件
- 3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。
基于Spring的AOP简单实现
这里以注解的方式来实现AOP,更贴近现在的使用
pom.xml添加依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.3.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
</dependencies>
这里面需要引用spring的几个jar包,包括core、beans、context、aop,还要引用aspectjweaver这个
定义要切入的业务类,这里简单定义一个新增方法即可
@Service
public class UserService {
public void add() {
System.out.println("新增数据成功");
}
}
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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!-- spring从该包下面自动扫描组件 -->
<context:component-scan base-package="com.critc"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean class="com.critc.aop.LogAspect"/>
</beans>
这里面最核心的两句是
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean class="com.critc.aop.LogAspect"/>
启用AOP,且定义一个切入类是com.critc.aop.LogAspect
定义切面程序LogAspect.java
@Aspect
public class LogAspect {
/**
* 方法开始前执行
*/
@Before("execution(* com.critc.service..*.*(..)) ")
private void beforeMethod() {
System.out.println("the Method begins........");
}
/**
* 方法结束后执行
*/
@After("execution(* com.critc.service..*.*(..)) ")
private void afterMethod() {
// TODO Auto-generated method stub
System.out.println("The Method after ................");
}
/**
* 返回后执行
* @param joinPoint
* @param result
*/
@AfterReturning(value = "execution(* com.critc.service..*.*(..)) ", returning = "result")
public void AfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("The Method after ................" + result);
}
/**
* 抛出异常执行
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "execution(* com.critc.service..*.*(..)) ", throwing = "e")
public void AfterThrowing(JoinPoint joinPoint, Exception e) {
System.out.println("The Method afterThrowing................"
+ e.getMessage().toString());
}
/**
* 环绕执行
* @param pjp
* @return
*/
@Around(value = "execution(* com.critc.service..*.*(..)) ")
public Object aroundTest(ProceedingJoinPoint pjp) {
String methodName = pjp.getSignature().getName();
Object object = null;
try {
// 前置通知
System.out.println("The Method " + methodName + "before................");
// object = pjp.proceed();
object = "view/index";
// 返回通知
System.out.println(object);
} catch (Throwable e) {
// TODO Auto-generated catch block
// 异常通知
System.out.println(e.getMessage().toString());
}
System.out.println("The Method " + methodName + "after................");
return object;
}
}
上面这个例子把aop的大概例子讲了一下,后面我会详细讲述Spring AOP在实际中的应用,比如异常处理、日志处理、权限控制。
网友评论