分类
- 前置通知
- 在目标类的方法执行之前执行。
- 配置文件信息:
- 应用:可以对方法的参数来做校验
- 最终通知
- 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
- 在配置文件中编写具体的配置:
- 应用:例如像释放资源
- 后置通知
- 方法正常执行后的通知。
- 在配置文件中编写具体的配置:
- 应用:可以修改方法的返回值
- 异常抛出通知
- 在抛出异常后通知
- 在配置文件中编写具体的配置:
- 应用:包装异常的信息
- 环绕通知
- 方法的执行前后执行。
- 在配置文件中编写具体的配置:
- 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。
注意:AOP依赖与IoC,在spring里不是使用注解就是配置xml,所以,下面会用到配置文件进行配置通知
步骤
使用maven导包spring-context,会自动引入spring-aop
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
提供代理对象PhoneImpl.java
public class PhoneImpl {
public void product5S() {
System.out.println("生产iPhone 5S中");
}
//为下面的异常通知使用
public void testException() {
//设置异常
int i=/;
System.out.println("这是异常下面的代码");
}
}
提供一个
applicationContext.xml
,提供一个
Test.java
测试类
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
</beans>
前置通知
提供代理对象
BeforeProxy.java
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeProxy implements MethodBeforeAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("前置通知");
}
}
配置文件applicationContext.xml中配置前置通知
<!-- 创建要代理的对象 一下的id随便起名字-->
<bean id="phone" class="com.phone.PhoneImpl"></bean>
<!-- 创建增强对象,也就是通知对象 -->
<bean id="before" class="com.proxy.BeforeProxy"></bean>
<!-- 处理要代理的对象与增强对象之间的关系 -->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置要代理的对象,也就是目标对象 -->
<property name="target" ref="phone"></property>
<!-- 设置拦截器,也就是增强对象 注意使用的是value属性-->
<property name="interceptorNames" value="before"></property>
<!-- 如果为true表示jdk代理,要有接口,如果为false表示可以没有接口 -->
<property name="optimize" value="false"></property>
</bean>
测试
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
PhoneImpl phone=(PhoneImpl)applicationContext.getBean("proxy");
phone.product5S();
运行结果
前置通知
生产iPhone 5S中
后置通知
提供后置通知对象
AfterProxy.java
,注意实现的接口
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class AfterProxy implements AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println("后置通知");
}
}
配置文件applicationContext.xml中增加bean
<!-- 创建要代理的对象 一下的id随便起名字-->
<bean id="phone" class="com.henu.phone.PhoneImpl"></bean>
<!-- 创建增强对象,也就是通知对象 -->
<bean id="before" class="com.henu.proxy.BeforeProxy"></bean>
<!--增加的地方-->
<bean id="after" class="com.henu.proxy.AfterProxy"></bean>
<!-- 处理要代理的对象与增强对象之间的关系 -->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置要代理的对象,也就是目标对象 -->
<property name="target" ref="phone"></property>
<!-- 设置拦截器,也就是增强对象 注意使用的是value属性-->
<!--修改的地方,同时提供前置和后置通知,这个地方为什么不用ref引用呢,如果用ref会报错,这里可以引入多个对象,如果用ref只能引入一个对象-->
<property name="interceptorNames" value="after,before"></property>
<!-- 如果为true表示jdk代理,要有接口,如果为false表示可以没有接口 -->
<property name="optimize" value="false"></property>
</bean>
运行结果
前置通知
生产iPhone 5S中
后置通知
环绕通知
提供
RoundProxy.java
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class RoundProxy implements MethodInterceptor{
//可以替代目标方法
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("环绕通知");
//如果没有下面这些,执行的时候目标方法会被替代,只显示上面的一句话
invocation.proceed();//执行原来的方法
return null;
}
}
修改配置文件
<!-- 创建要代理的对象 一下的id随便起名字-->
<bean id="phone" class="com.henu.phone.PhoneImpl"></bean>
<!-- 创建增强对象,也就是通知对象 -->
<bean id="before" class="com.henu.proxy.BeforeProxy"></bean>
<bean id="after" class="com.henu.proxy.AfterProxy"></bean>
<bean id="round" class="com.henu.proxy.RoundProxy"></bean>
<!-- 处理要代理的对象与增强对象之间的关系 -->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置要代理的对象,也就是目标对象 -->
<property name="target" ref="phone"></property>
<!-- 设置拦截器,也就是增强对象 注意使用的是value属性-->
<property name="interceptorNames" value="after,before,round"></property>
<!-- 如果为true表示jdk代理,要有接口,如果为false表示可以没有接口 -->
<property name="optimize" value="false"></property>
</bean>
运行结果
前置通知
环绕通知
生产iPhone 5S中
后置通知
异常通知
提供异常通知代理类
ExceptionProxy.java
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
//该接口没有任何方法需要实现,需要自己写
public class ExceptionProxy implements ThrowsAdvice{
/*public void afterThrowing(Throwable throwable) {
}*/
public void afterThrowing(Method m,Object[] os,Object obj,Throwable throwable) {
System.out.println("异常通知");
}
}
修改配置文件
<!-- 创建要代理的对象 一下的id随便起名字-->
<bean id="phone" class="com.henu.phone.PhoneImpl"></bean>
<!-- 创建增强对象,也就是通知对象 -->
<bean id="before" class="com.henu.proxy.BeforeProxy"></bean>
<bean id="after" class="com.henu.proxy.AfterProxy"></bean>
<bean id="round" class="com.henu.proxy.RoundProxy"></bean>
<bean id="throwss" class="com.henu.proxy.ExceptionProxy"></bean>
<!-- 处理要代理的对象与增强对象之间的关系 -->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置要代理的对象,也就是目标对象 -->
<property name="target" ref="phone"></property>
<!-- 设置拦截器,也就是增强对象 注意使用的是value属性-->
<property name="interceptorNames" value="after,before,round,throwss"></property>
<!-- 如果为true表示jdk代理,要有接口,如果为false表示可以没有接口 -->
<property name="optimize" value="false"></property>
</bean>
修改测试类
Test.java
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
PhoneImpl phone=(PhoneImpl)applicationContext.getBean("proxy");
//要修改的地方
phone.testException();
测试结果,打印出了 异常通知
前置通知
环绕通知
异常通知
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.henu.phone.PhoneImpl.testException(PhoneImpl.java:)
at com.henu.phone.PhoneImpl$$FastClassBySpringCGLIB$$edc957f1.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at com.henu.proxy.RoundProxy.invoke(RoundProxy.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:)
at com.henu.phone.PhoneImpl$$EnhancerBySpringCGLIB$$d04c134a.testException(<generated>)
at com.henu.proxy.Test.main(Test.java:)
最终通知
无论目标方法是否遇到异常都会执行,相当于代码中的finnaly
。。。这个以后补充。。。