AOP 介绍
Spring AOP是 Spring 框架的核心内容
AOP 是一种思想,是面向切面的编程,与面向对象编程不同
Spring AOP 实现基于 Java 的代理机制
在面向切面编程中,通常把功能分为核心业务功能与周边功能,切面功能就相当于周边功能。
通常是将核心业务功能与周边功能独立进行开发,最后联合到一起
Spring AOP 的有关术语:
1、切面(Aspect)
切面是对象操作过程中的截面,它是一段程序代码,这段代码将被植入到程序的流程中
2、连接点(Joint Point)
对象操作过程中的某个阶段点,它实际上是对象的一个操作,如对象调用了某个方法、读写对象的实例或者某个方法抛出了异常等。
3、切入点
切入点是连接点的集合,切面通过切入点植入到程序中的
4、通知(Advice)
它是某个切入点被横切之后采取的处理逻辑,指在切入点处拦截程序后通过通知来执行切面
5、目标对象(Target)
所有被通知的对象或者被代理的对象都可作为目标对象。AOP 会注意目标对象的变动,并随时准备向目标对象执行切面功能
6、织入
织入是将切面功能应用到目标对象的过程,有代理工厂并创建一个代理对象,这个代理可以作为目标对象执行切面功能
AOP 的简单实现
一、利用 Spring AOP 使日志输出 与方法分离,以在调用目标方法之前执行日志输出
1、创建类 Target,它是被代理的目标对象,在调用其方法前进行输出日志
package com.mr.target;
public class Target {
// 程序执行的方法
public void execute(String name) {
System.out.println("程序开始执行:" + name);
}
}
2、创建类 LoggerExecute,它是通知,拦截目标对象的 execute 方法,并执行日志输出,通过它来执行切面
package com.mr.inform;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LoggerExecute implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
before();
invocation.proceed();
return null;
}
private void before() {
System.out.println("程序开始执行!");
}
}
3、编写主类,创建代理
package com.mr.main;
import org.springframework.aop.framework.ProxyFactory;
import com.mr.inform.LoggerExecute;
import com.mr.target.Target;
public class Manager {
public static void main(String[] args) {
// 创建目标对象
Target target = new Target();
// 代理工厂
ProxyFactory diFactory = new ProxyFactory();
// 加入通知
diFactory.addAdvice(new LoggerExecute());
// 加入目标对象
diFactory.setTarget(target);
Target proxy = (Target) diFactory.getProxy();
// 代理执行方法
proxy.execute("AOP 的简单实现!");
}
}
运行结果:

总结:
这个实际上就是在运行 Target的execute() 方法之前,调用了通知里面的方法
可以理解为通知拦截了Target对象,运行它其中的代码
目标对象运行前的代码==》目标对象运行时的代码==》目标对象运行后的代码
这样就可以看到 这是一个简单的处理逻辑过程
通知中的核心代码是:
before();
invocation.proceed();
before() 是执行execute() 方法之前运行的代码程序
而 invocation.proceed() 方法是运行目标对象程序
在它之前或之后的代码(方法)可以自己定义
二、另一种AOP方式
1、创建业务类 ProductService(目标对象)
package com.how2java.service;
public class ProductService {
public void doSomeService() {
System.out.println("doSomeService");
}
}
2、创建日志切面类 LoggerAspect(通知)
package com.how2java.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
// 执行之前
System.out.println("start log:" + joinPoint.getSignature().getName());
// 执行目标对象的代码
Object object = joinPoint.proceed();
//执行之后
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
3、创建测试类 TestSpring (主类)
package com.how2java.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.how2java.service.ProductService;
public class TestSpring {
public static void main(String[] args) {
// 装载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
// 获取目标对象
ProductService s = (ProductService) context.getBean("s");
// 调用方法
s.doSomeService();
}
}
4、配置 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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.how2java.pojo"/>
<!--声明目标对象-->
<bean name="s" class="com.how2java.service.ProductService">
</bean>
<!--声明日志切面,相当于通知-->
<bean id="loggerAspect" class="com.how2java.aspect.LoggerAspect"/>
<!--处理逻辑-->
<aop:config>
<aop:pointcut id="loggerCutpoint"
expression=
"execution(* com.how2java.service.ProductService.*(..)) "/>
<aop:aspect id="logAspect" ref="loggerAspect">
<aop:around pointcut-ref="loggerCutpoint" method="log"/>
</aop:aspect>
</aop:config>
</beans>
运行结果:
这种AOP方法是在配置文件中说明的,与第一种调用代理工厂的方法不同
但是目标对象类 和 通知类(参数类型不同)中的代码基本都相同