-
Spring AOP : 面向方面(切面)编程,用于在模块化方面的横切关注点。
可以简单的理解为spring提供了拦截器,用来拦截一些过程。比如一个方法执行前,执行返回结果后,执行抛出异常后。添加额外的处理(通知)
在Spring AOP中,有 4 种类型通知(advices)的支持:
-
通知(Advice)之前 - 该方法执行前运行
-
实现 MethodBeforeAdvice 接口 , 并配置 bean , 通过 代理对象 进行拦截
-
-
通知(Advice)返回之后 – 运行后,该方法返回一个结果
-
实现 AfterReturningAdvice 接口
-
-
通知(Advice)抛出之后 – 运行方法抛出异常后,
-
实现 ThrowsAdvice 接口
-
- 环绕通知 – 环绕方法执行运行,结合以上这三个通知。
- TODO 未知原因没后实现
以上四种配置bean方法基本类似
实例(通知(Advice)之前):
userServiceBean
package tao.test.service;
public class UserService {
private String uName;
private int uAge;
public String getuName() {
return uName;
}
public void setuName(String uName) {
this.uName = uName;
}
public int getuAge() {
return uAge;
}
public void setuAge(int uAge) {
this.uAge = uAge;
}
public void printName(){
System.out.println("Name");
}
}
HijackBeforeMethod
package com.cn.utils;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* @author Tao
* @since 2019/01/14
*
*/
public class HijackBeforeMethod implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("HijackBeforeMethod : Before method !");
System.out.println("------------------------------");
System.out.println("参数:" + args.toString());
System.out.println("参数:" + target);
System.out.println("------------------------------");
}
}
applicationContext.xml (部分 --上面两个java和代理的配置)
<bean id="userServiceBean" class="tao.test.service.UserService" />
<!-- ************************************************************************************************* -->
<bean id="hijackBeforeMethodBean" class="com.cn.utils.HijackBeforeMethod"></bean>
<!-- 代理对象1 方法执行之前 -->
<bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>hijackBeforeMethodBean</value>
</list>
</property>
</bean>
<!-- ************************************************************************************************* -->
applicationContext.xml (全部 -- 包括后面两种方法的配置 和 拦截单个方法的配置(此部分可以忽略))
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="customerService" class="tao.test.service.CustomerService">
<property name="name" value=" Tao " />
<property name="url" value="www.kcss.com.cn" />
<property name="userService" ref="userServiceBean"></property>
</bean>
<bean id="userServiceBean" class="tao.test.service.UserService" />
<!-- ************************************************************************************************* -->
<bean id="hijackBeforeMethodBean" class="com.cn.utils.HijackBeforeMethod"></bean>
<!-- 代理对象1 方法执行之前 -->
<bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>hijackBeforeMethodBean</value>
</list>
</property>
</bean>
<!-- ************************************************************************************************* -->
<bean id="hijackAfterMethodBean" class="com.cn.utils.HijackAfterMethod" />
<!-- 代理对象2 方法返回结果之后 -->
<bean id="customerServiceProxyAfter" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>hijackAfterMethodBean</value>
</list>
</property>
</bean>
<!-- ************************************************************************************************* -->
<bean id="HijackThrowExceptionBean" class="com.cn.utils.HijackThrowException"></bean>
<!-- 代理对象 拦截抛出异常后 -->
<bean id="customerServiceProxyThrowAfter" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>HijackThrowExceptionBean</value>
</list>
</property>
</bean>
<!-- ************************************************************************************************* -->
<!-- 通过“切入点”和“advisor”拦截printName()方法。 创建NameMatchMethodYiibaicut切入点bean,并提出要在“mappedName”属性值来拦截方法名。 -->
<bean id="customerPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="printName" />
</bean>
<!-- 创建 DefaultYiibaicutAdvisor 通知 bean,通知和切入点相关联。 -->
<bean id="customerAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="customerPointcut" />
<property name="advice" ref="hijackAfterMethodBean" />
</bean>
<!-- 创建代理 -->
<bean id="customerServiceProxyByName" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>customerAdvisor</value>
</list>
</property>
</bean>
<!-- 方法2 使用 NameMatchMethodPointcutAdvisor 可以减少一个bean 配置, 它将 name 和 advice
放在一起配置了 -->
<bean id="customerAdvisor2"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="printName" />
<property name="advice" ref="hijackAfterMethodBean" />
</bean>
<!-- 创建代理 -->
<bean id="customerServiceProxyByName2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>customerAdvisor2</value>
</list>
</property>
</bean>
<!-- ************************************************************************************************* -->
<!-- 通过使用正则表达式匹配切入点方法的名称 – RegexpMethodPointcutAdvisor. -->
<bean id="regexpMethodPointcutAdvisorBean"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="hijackBeforeMethodBean" />
</bean>
<bean id="customerServiceProxyByEl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerService" />
<property name="interceptorNames">
<list>
<value>regexpMethodPointcutAdvisorBean</value>
</list>
</property>
</bean>
<!-- ************************************************************************************************* -->
</beans>
App.java 测试类
package tao.test.test;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import tao.test.service.CustomerService;
/**
* 测试类
*
* @since 2019/01/14
* @author b1707007
*
*/
public class App {
/**
*
* 直接执行方法,没有拦截
*/
@Test
public void test1() {
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
CustomerService cust = appContext.getBean(CustomerService.class, "customerService");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
System.out.println("出错啦! : " + e);
} finally {
appContext.close();
}
}
/**
* AOP CustomerService 所有方法执行前都会先执行 HijackBeforeMethod.before(); 之前通知:
* 在方法调用时,进行拦截,在方法执行之前进行通知(处理)
*
* @author b1707007
*/
@Test
public void test2() {
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} finally {
appContext.close();
}
}
/**
* CustomerService 所有方法执行前都会先执行 HijackAfterMethod.afterReturning(); 之后通知:
* 在方法调用时,进行拦截,在方法执行之后进行通知(处理)
*/
@Test
public void test3() {
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxyAfter");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} finally {
appContext.close();
}
}
/**
* 拦截,方法执行抛出异常后 通知
*/
@Test
public void test4() {
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxyThrowAfter");
System.out.println("*************************");
try {
cust.printThrowException();
} finally {
appContext.close();
}
}
/**
* 按名称匹配拦截的方法--切入点
*/
@Test
public void test5() {
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxyByName");
try {
System.out.println("url: *************************");
cust.printURL();
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
} finally {
appContext.close();
}
}
/**
* 按正则表达式匹配拦截的方法--切入点
*/
@Test
public void test6() {
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxyByEl");
try {
System.out.println("url: *************************");
cust.printURL();
System.out.println("url:*************************");
cust.printName();
System.out.println("*************************");
} finally {
appContext.close();
}
}
/**
* 按名称匹配拦截的方法--切入点
* 配置方法2
*/
@Test
public void test7(){
AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxyByName2");
try {
System.out.println("url: *************************");
cust.printURL();
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
} finally {
appContext.close();
}
}
}