AOP详解
- 基本定义
- 通知
是指拦截到JointPoint之后需要做的事情
spring的五种通知类型
1) Before通知,即在方法调用之前调用通知
2) After通知,即方法完成之后调用通知,无论方法执行成功与否
3) After-returning通知,即在方法执行成功之后调用通知
4) After-throwing通知,即在方法抛出异常后调用通知
5) Around通知,即环绕通知- 连接点(Joinpoint)
是指哪些方法可以被拦截- 切入点(Pointcut)
要对哪些方法进行拦截- 切面(Aspect)
切面是通知和切入点的集合。通知和切入点共同定义了切面的全部功能–它是什么,在何时何处完成其功能- 引介(Introduction)
引入允许我们向现有的类中添加方法或属性- 目标对象(Target)
代理的目标对象,需要被增强的对象- 织入(Weaving)
是指把增强应用到目标对象来创建新的代理对象的过程- 代理(Proxy)
一个类被AOP织入增强后,就产生一个结果代理类
- 前置通知
- 接口
package com.jd.wang;
public interface ISomeService {
public void doFirst();
}
- 实现
package com.jd.wang;
public class SomeService implements ISomeService {
public void doFirst() {
// TODO Auto-generated method stub
System.out.println("doFirst");
}
}
- 通知
package com.jd.wang;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
// TODO Auto-generated method stub
System.out.print("执行前置通知方法");
}
}
-
注册
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <bean id="someService" class="com.jd.wang.SomeService"></bean> <bean id="myAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean> <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"></property> <property name="interceptorNames" value="myAdvice"></property> </bean> </beans>
注:此处使用了代理工厂bean(proxyfactorybean)
-
后置通知
package com.jd.wang; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class MyAfterReturningAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { // TODO Auto-generated method stub System.out.println("执行后置通知"); } }
-
环绕通知
package com.jd.wang; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { // TODO Auto-generated method stub System.out.println("目标方法执行之前"); Object result = invocation.proceed(); System.out.println("目标方法执行之后"); return result; } }
-
异常通知
package com.jd.wang; import org.springframework.aop.ThrowsAdvice; public class MyThrowsAdvice implements ThrowsAdvice { //当目标方法抛出抛出与指定类型的类型有is-a类型时执行当前方法 public void afterThrowing(Exception ex) { System.out.println("执行异常通知方法"); } }
-
配置多个通知
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <bean id="someService" class="com.jd.wang.SomeService"></bean> <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean> <bean id="myBeAfterAdvice" class="com.jd.wang.MyAfterReturningAdvice"></bean> <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"></property> <property name="interceptorNames"> <array> <value>myBeforeAdvice</value> <value>myBeAfterAdvice</value> </array> </property> </bean> </beans>
-
配置CGL代理
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <bean id="someService" class="com.jd.wang.SomeService"></bean> <bean id="myBeAfterAdvice" class="com.jd.wang.MyAfterReturningAdvice"></bean> <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"></property> <property name="interceptorNames" value="myBeAfterAdvice"></property> <property name="proxyTargetClass" value="true"></property> </bean> </beans>
-
名称匹配方法切入点顾问
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <bean id="someService" class="com.jd.wang.SomeService"></bean> <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean> <bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myBeforeAdvice"></property> <!-- 指定切入点 --> <property name="mappedName" value="doFirst"></property> //此处可以使用通配符 </bean> <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"></property> <property name="interceptorNames"> <array> <value>myAdvisor</value> </array> </property> </bean> </beans>
-
正则匹配方法切入点顾问
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <bean id="someService" class="com.jd.wang.SomeService"></bean> <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean> <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myBeforeAdvice"></property> <!-- 指定切入点,切入点是对于方法的全限定名而言的 --> <property name="patterns" value=".*doFirst,|.*doSecond"></property> </bean> <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"></property> <property name="interceptorNames"> <array> <value>myAdvisor</value> </array> </property> </bean> </beans>
-
默认自动代理生成器
- 解决代理工厂bean无法处理有多个目标bean的情况
- 配置如下
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
<bean id="someService" class="com.jd.wang.SomeService"></bean>
<bean id="someService2" class="com.jd.wang.SomeService"></bean>
<bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="myBeforeAdvice"></property>
<!-- 指定切入点 -->
<property name="pattern" value=".*doFirst"></property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>
-
Bean名称自动代理生成器
扫描二维码关注公众号,回复: 5122131 查看本文章<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <bean id="someService" class="com.jd.wang.SomeService"></bean> <bean id="someService2" class="com.jd.wang.SomeService"></bean> <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean> <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myBeforeAdvice"></property> <!-- 指定切入点 --> <property name="pattern" value=".*doFirst"></property> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> <property name="beanName" value="someService"></property> <property name="interceptorNames" value="myAdvisor"></property> </bean> </beans>
注:ProxyFactoryBean先有代理对象,将被代理对象传入代理后生成代理;自动代理基于后处理Bean,在Bean的生成过程中就会生成代理对象且把代理对象返回。
可以通过beanNames设置多个代理对象
- AspectJ对AOP的实现
切入点表达式
- execution
(
[modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
[declaring-type-pattern]全限定类型
name-pattern(param-pattern)方法名(类型名)
[throws-pattern] 抛出异常类型
)
- 符号的含义
符号 | 含义 |
---|---|
* | 0或多个任意字符 |
.. | 用在方法参数中表示任意多个参数;用在包名后表示当前包及其子包路径 |
+ | 用在类名后表示当前类及其子类;用在接口后表示当前接口及其实现类 |
定义切面
package com.jd.wang.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("execution(* *..ISomeService.doFirst(..))")
public void before(){
System.out.println("执行前置通知");
}
}
接口与类
package com.jd.wang.annotation;
public interface ISomeService {
public void doFirst();
public void doSecond();
}
package com.jd.wang.annotation;
public class SomeService implements ISomeService {
public void doFirst() {
// TODO Auto-generated method stub
System.out.println("doFirst");
}
public void doSecond()
{
System.out.println("doSecond");
}
}
测试类
package com.jd.wang.annotation;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test01()
{
String resource="com/jd/wang/annotation/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
ISomeService service = (ISomeService) ac.getBean("myService");
service.doFirst();
service.doSecond();
}
}
注册
<?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" xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
<bean id="myAspect" class="com.jd.wang.annotation.MyAspect"></bean>
<bean id="myService" class="com.jd.wang.annotation.SomeService"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
后置通知
package com.jd.wang.annotation;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("execution(* *..ISomeService.doFirst(..))")
public void before(){
System.out.println("前置通知:");
}
@AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
public void afteringReturning(Object result)
{
System.out.println("后置通知"+result);
}
}
环绕通知
package com.jd.wang.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("execution(* *..ISomeService.doFirst(..))")
public void before(){
System.out.println("前置通知:");
}
@AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
public void afteringReturning(Object result)
{
System.out.println("后置通知"+result);
}
@Around("execution(* *..ISomeService.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable
{
System.out.println("执行方法之前");
Object result = pjp.proceed();
System.out.println("执行方法之后");
return result;
}
}
异常通知
package com.jd.wang.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("execution(* *..ISomeService.doFirst(..))")
public void before(){
System.out.println("前置通知:");
}
@AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
public void afteringReturning(Object result)
{
System.out.println("后置通知"+result);
}
@Around("execution(* *..ISomeService.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable
{
System.out.println("执行方法之前");
Object result = pjp.proceed();
System.out.println("执行方法之后");
return result;
}
@AfterThrowing(value="execution(* *..ISomeService.doFirst(..))",throwing="ex")
public void myAfterThrowing(Exception ex)
{
System.out.println("异常通知方法");
}
}
最终通知
package com.jd.wang.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before("execution(* *..ISomeService.doFirst(..))")
public void before(){
System.out.println("前置通知:");
}
@AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
public void afteringReturning(Object result)
{
System.out.println("后置通知"+result);
}
@Around("execution(* *..ISomeService.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable
{
System.out.println("执行方法之前");
Object result = pjp.proceed();
System.out.println("执行方法之后");
return result;
}
@AfterThrowing(value="execution(* *..ISomeService.doFirst(..))",throwing="ex")
public void myAfterThrowing(Exception ex)
{
System.out.println("异常通知方法");
}
@After(value="execution(* *..ISomeService.doFirst(..))")
public void myAfter()
{
System.out.println("最终通知");
}
}
- 基于XML的AOP
- 第一种配置文件
<?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" xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
<bean id="myAspect" class="com.jd.wang.annotation.MyAspect"></bean>
<bean id="myService" class="com.jd.wang.annotation.SomeService"></bean>
<!-- AOP配置 -->
<aop:config>
<aop:aspect ref="myAspect">
<aop:after method="myAfter" pointcut="execution(* *..ISomeService.doFirst(..))"/>
<aop:after method="myAfter(org.aopalliance.intercept.Joinpoint)" pointcut="execution(* *..ISomeService.doFirst(..))"/>
</aop:aspect>
</aop:config>
</beans>
- 第二种配置文件
<?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" xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
<bean id="myAspect" class="com.jd.wang.annotation.MyAspect"></bean>
<bean id="myService" class="com.jd.wang.annotation.SomeService"></bean>
<!-- AOP配置 -->
<aop:config>
<aop:pointcut expression="execution(* *..ISomeService.doFirst(..))" id="doFirstCut"/>
<aop:aspect ref="myAspect">
<aop:after method="myAfter" pointcut-ref="doFirstCut"/>
</aop:aspect>
</aop:config>
</beans>