建议先看一下代理模式:https://blog.csdn.net/dengjili/article/details/82802614
在Spring AOP中,有 4 种类型通知(advices)的支持:
- 通知(Advice)之前 - 该方法执行前运行
- 通知(Advice)返回之后 – 运行后,该方法返回一个结果
- 通知(Advice)抛出之后 – 运行方法抛出异常后,
- 环绕通知 – 环绕方法执行运行,结合以上这三个通知。
下载相关代码,根据描述运行
相关代码
https://github.com/dengjili/springaop
先看一个spring 例子
被代理类
package priv.dengjl.springaop.service;
/**
* 业务类
*
* @author it
*/
public class TestService {
private String name;
private String url;
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public void printName() {
System.out.println("名称 : " + this.name);
}
public void printURL() {
System.out.println("网址 : " + this.url);
}
public void printThrowException() {
throw new IllegalArgumentException();
}
}
before动作
package priv.dengjl.springaop.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class TestBeforeAdvice implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("前置通知【方法1】!!!,执行方法前");
}
}
其他类似,后面给出工程代码
spring配置信息
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- 基础bean -->
<bean id="testService" class="priv.dengjl.springaop.service.TestService">
<property name="name" value="呵呵哒" />
<property name="url" value="www.mmp.com" />
</bean>
<!-- 代理类bean -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 被代理对象 -->
<property name="target" ref="testService" />
<!-- 配置被代理对象需要处理的动作 -->
<property name="interceptorNames">
<list>
<value>testBeforeAdvice</value>
<value>testBeforeAdvice2</value>
<value>testAfterAdvice</value>
<value>testAfterAdvice2</value>
<value>testThrowException</value>
<value>testAroundMethod</value>
</list>
</property>
</bean>
<bean id="testBeforeAdvice" class="priv.dengjl.springaop.aop.TestBeforeAdvice" />
<bean id="testBeforeAdvice2" class="priv.dengjl.springaop.aop.TestBeforeAdvice2" />
<bean id="testAfterAdvice" class="priv.dengjl.springaop.aop.TestAfterAdvice" />
<bean id="testAfterAdvice2" class="priv.dengjl.springaop.aop.TestAfterAdvice2" />
<bean id="testThrowException" class="priv.dengjl.springaop.aop.TestThrowException" />
<bean id="testAroundMethod" class="priv.dengjl.springaop.aop.TestAroundMethod" />
</beans>
测试类
package priv.dengjl.springaop.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
TestService cust = (TestService) appContext.getBean("serviceProxy");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
System.out.println("有异常发生");
System.out.println("*************************");
}
}
}
测试结果
*************************
前置通知【方法1】!!!,执行方法前
前置通知【方法2】!!!,执行方法前
TestAroundMethod环绕 before
名称 : 呵呵哒
TestAroundMethod环绕 after
后置通知【方法2】!!!,执行方法后
后置通知【方法1】!!!,执行方法后
*************************
前置通知【方法1】!!!,执行方法前
前置通知【方法2】!!!,执行方法前
TestAroundMethod环绕 before
网址 : www.mmp.com
TestAroundMethod环绕 after
后置通知【方法2】!!!,执行方法后
后置通知【方法1】!!!,执行方法后
*************************
前置通知【方法1】!!!,执行方法前
前置通知【方法2】!!!,执行方法前
TestAroundMethod环绕 before
TestAroundMethod环绕 after异常
抛出异常后,处理!!!
有异常发生
*************************
配置信息讲解
配置映射关系
Advisor入门
配置文件applicationContextAdvisor.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- 基础bean -->
<bean id="testService" class="priv.dengjl.springaop.service.TestService">
<property name="name" value="呵呵哒" />
<property name="url" value="www.mmp.com" />
</bean>
<!-- 切入点,想拦截哪些方法,更加细粒度 -->
<bean id="testPointcut" class="priv.dengjl.springaop.advisor.MyPointcut">
<property name="addMappingName" value="printName"/>
</bean>
<!-- 使用DefaultPointcutAdvisor -->
<bean id="testAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<ref bean="testPointcut" />
</property>
<property name="advice">
<ref bean="testBeforeAdvice"/>
</property>
</bean>
<!-- 使用RegexpMethodPointcutAdvisor -->
<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<!-- 参考java pattern类正则表达式配置 这是匹配printURL方法 -->
<value>.*URL.*</value>
</list>
</property>
<property name="advice">
<ref bean="testAfterAdvice"/>
</property>
</bean>
<!-- 使用NameMatchMethodPointcutAdvisor *完全匹配 -->
<bean id="myAroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedNames">
<list>
<value>*ThrowException*</value>
</list>
</property>
<property name="advice">
<ref bean="testAroundMethod" />
</property>
</bean>
<!-- 代理类bean -->
<bean id="serviceProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 被代理对象 -->
<property name="target" ref="testService" />
<!-- 配置被代理对象需要处理的动作 -->
<property name="interceptorNames">
<list>
<value>testAdvisor</value>
<value>regexpAdvisor</value>
<value>myAroundAdvisor</value>
</list>
</property>
</bean>
<bean id="testBeforeAdvice" class="priv.dengjl.springaop.aop.TestBeforeAdvice" />
<bean id="testBeforeAdvice2" class="priv.dengjl.springaop.aop.TestBeforeAdvice2" />
<bean id="testAfterAdvice" class="priv.dengjl.springaop.aop.TestAfterAdvice" />
<bean id="testAfterAdvice2" class="priv.dengjl.springaop.aop.TestAfterAdvice2" />
<bean id="testThrowException" class="priv.dengjl.springaop.aop.TestThrowException" />
<bean id="testAroundMethod" class="priv.dengjl.springaop.aop.TestAroundMethod" />
</beans>
测试类
package priv.dengjl.springaop.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*
*/
public class AppAdvisor
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "applicationContextAdvisor.xml" });
TestService cust = (TestService) appContext.getBean("serviceProxy");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
System.out.println("有异常发生");
System.out.println("*************************");
}
}
}
测试结果
根据配置结果拦截
*************************
前置通知【方法1】!!!,执行方法前
名称 : 呵呵哒
*************************
网址 : www.mmp.com
后置通知【方法1】!!!,执行方法后
*************************
TestAroundMethod环绕 before
TestAroundMethod环绕 after异常
有异常发生
*************************
配置信息讲解
配置映射关系,最简单的方式
正则方式和名称
Spring自动代理创建者实例与动态代理
配置文件applicationContextAutoProxy.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- 基础bean -->
<bean id="testService" class="priv.dengjl.springaop.service.TestService">
<property name="name" value="呵呵哒" />
<property name="url" value="www.mmp.com" />
</bean>
<!-- 切入点,想拦截哪些方法,更加细粒度 -->
<bean id="testPointcut" class="priv.dengjl.springaop.advisor.MyPointcut">
<property name="addMappingName" value="printName"/>
</bean>
<!-- 使用DefaultPointcutAdvisor -->
<bean id="testAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<ref bean="testPointcut" />
</property>
<property name="advice">
<ref bean="testBeforeAdvice"/>
</property>
</bean>
<!-- 使用RegexpMethodPointcutAdvisor -->
<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<!-- 参考java pattern类正则表达式配置 这是匹配printURL方法 -->
<value>.*URL.*</value>
</list>
</property>
<property name="advice">
<ref bean="testAfterAdvice"/>
</property>
</bean>
<!-- 使用NameMatchMethodPointcutAdvisor *完全匹配 -->
<bean id="myAroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedNames">
<list>
<value>*ThrowException*</value>
</list>
</property>
<property name="advice">
<ref bean="testAroundMethod" />
</property>
</bean>
<!-- 静态代理类bean -->
<!-- <bean id="serviceProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
被代理对象
<property name="target" ref="testService" />
配置被代理对象需要处理的动作
<property name="interceptorNames">
<list>
<value>testAdvisor</value>
<value>regexpAdvisor</value>
<value>myAroundAdvisor</value>
</list>
</property>
</bean> -->
<!-- 动态代理类bean -->
<!-- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>testAdvisor</value>
<value>regexpAdvisor</value>
<value>myAroundAdvisor</value>
</list>
</property>
</bean> -->
<!-- DefaultAdvisorAutoProxyCreator 是非常强大的,如果有 bean 相关连,Spring会自动创建一个代理,不建议使用,应当显示说明 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
<bean id="testBeforeAdvice" class="priv.dengjl.springaop.aop.TestBeforeAdvice" />
<bean id="testBeforeAdvice2" class="priv.dengjl.springaop.aop.TestBeforeAdvice2" />
<bean id="testAfterAdvice" class="priv.dengjl.springaop.aop.TestAfterAdvice" />
<bean id="testAfterAdvice2" class="priv.dengjl.springaop.aop.TestAfterAdvice2" />
<bean id="testThrowException" class="priv.dengjl.springaop.aop.TestThrowException" />
<bean id="testAroundMethod" class="priv.dengjl.springaop.aop.TestAroundMethod" />
</beans>
测试类
package priv.dengjl.springaop.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*
*/
public class AppAutoProxy
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "applicationContextAutoProxy.xml" });
TestService cust = (TestService) appContext.getBean("testService");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
System.out.println("有异常发生");
System.out.println("*************************");
}
}
}
配置信息讲解
配置映射