什么是AOP?
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于将核心关注点和横切关注点分离开来。
为什么要将这两种进行分离呢?或者说这样做有什么好处?
比如一个登陆功能,你可能需要在用户登陆前后进行权限校验,当用户登录进来购买物品时,也需要进行校验。当系统非常地庞大时,系统中进行权限验证的代码是非常多和散乱的,我们就想能不能将这些权限校验、日志记录等非业务逻辑功能的部分独立拆分开,并且在系统运行时需要的地方(连接点)进行动态插入运行,不需要的时候就不理,因此AOP就起作用了!
AOP中的基本概念
已经大致了解了AOP是个什么东西了,接下来了解一下AOP 的几个基本概念:
- 切面(Aspect)
切面是切点和通知的集合,一般单独作为一个类。通知和切点共同定义了关于切面的全部内容,它是什么时候,在何时和何处完成功能。
- 连接点(Join point)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
- 切点(Pointcut)
对连接点进行拦截的定义,指定一个通知将被引发的一系列连接点的集合。
- 通知(Adivce)
在特定的连接点,AOP框架执行的动作。
通知有5种类型:
- Before: 在方法被调用之前调用
- After: 在方法完成后调用通知,无论方法是否执行成功
- After-returning: 在方法成功执行之后调用通知
- After-throwing: 在方法抛出异常后调用通知
- Around: 通环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知
- 引入(Introduction)
添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。
- 织入(Weaving)
组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
Spring中的AOP
AOP思想的实现一般都是基于代理模式,在JAVA中一般采用JDK动态代理模式,但是我们都知道,JDK动态代理模式只能代理接口,如果要代理类那么就不行了。因此,Spring AOP 会这样子来进行切换,因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理,当你的真实对象有实现接口时,Spring AOP会默认采用JDK动态代理,否则采用cglib代理。
- 默认使用JDK动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
- 当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
接下来就是实现了:
定义接口(连接点)
package com.xm.aop;
public interface Action {
//登陆
public void login();
//购买
public void buy();
}
接口文件实现类,这是代理模式中真正的被代理人
package com.xm.aop;
public class ActionImpl implements Action {
public void login() {
System.err.println("上线!!!!");
}
public void buy() {
System.err.println("购买中!!!!");
}
}
切面
package com.xm.aop;
/**
* 权限
*/
public class Permission {
/**
* 登录校验
*/
public void beforeLogin() {
System.err.println("开始校验······");
}
/**
* 校验之后做一些处理(无论是否成功都做处理)
*/
public void handle() {
System.err.println("正在处理······");
}
}
然后是aop.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<bean id="ActionImpl1" class="com.xm.aop.Action1" />
<bean id="ActionImpl2" class="com.xm.aop.Action2" />
<bean id="Permission" class="com.xm.aop.Permission" />
<aop:config>
<!-- 定义一个切面-->
<aop:aspect id="permission" ref="Permission">
<!-- 定义切点 ,后面表示包括该接口中定义的所有方法都会被执行-->
<aop:pointcut id="point" expression="execution(*com.xm.aop.Action.*(..))" />
<!-- 定义通知 -->
<aop:before method="beforeLogin" pointcut-ref="point" />
<aop:after method="handle" pointcut-ref="point" />
</aop:aspect>
</aop:config>
</beans>
最后测试
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
Action aciton1 = (Action)ctx.getBean("ActionImpl1");
Action action2 = (Action)ctx.getBean("ActionImpl2");
aciton1.login();
aciton1.buy();
System.err.println("--------------------");
aciton2.login();
aciton2.buy();
}
}
结果如下
开始校验······
上线!!!!
正在处理······
开始校验······
购买中!!!!
正在处理······
--------------------
开始校验······
上线!!!!
正在处理······
开始校验······
购买中!!!!
正在处理······
上面是xml,还可以通过注解方式
首先在aop.xml中加入
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.xm.aop"></context:component-scan>
<!--开启注解扫描-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
实体类加上 @Component
然后是切面类,就大功告成了,很简单
package com.xm.aop;
/**
* 权限
*/
@Component // 加入IOC容器
@Aspect
public class Permission {
@Pointcut("execution(*com.xm.aop.Action.*(..))")//切入点
public void pointCut(){
}
/**
* 登录校验
*/
@Before("pointCut()")
public void beforeLogin() {
System.err.println("开始校验······");
}
/**
* 校验之后做一些处理(无论是否成功都做处理)
*/
@After("pointCut()")
public void handle() {
System.err.println("正在处理······");
}
}
以上就是AOP的简单实现,码了这么久,其实只是入门而已,之后还要去进行更深入的研究,加油~~~