Spring AOP-----------基础
Posted 没昵称可用
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring AOP-----------基础相关的知识,希望对你有一定的参考价值。
AOP概述
1、AOP术语
连接点:连接点好比一个类的方法,每一个方法都是一个连接点
切点:每个方法有大量的逻辑构成,可以将任何一个位置作为执行点,这个执行点作为切点。
增强:就是嵌入方法中的一段逻辑。
目标对象:织入增强的目标类。
引介:特殊的增强,为类加入方法和属性。
织入:将增强嵌入切点的过程。
代理:织入增强后产生的结果类。
切面:切入点+增强
创建增强类
前置增强
前置增强=连接点前+增强,增强只是针对所有的的连接点。前置增强的实现类为MethodBeforeAdvice。
前置增强的过程:1、创建代理工厂;2、创建目标类,也就是需要织入增强的类;3、通过MethodBeforeAdvice生成增强类;4、将增强类和目标类添加到代理工厂;5、生成目标代理。
实例:
创建目标类
package advice; public interface Waiter { void greetTo(String name); void serverTo(String name); }
package advice; public class NaiveWaiter implements Waiter { @Override public void greetTo(String name) { // TODO Auto-generated method stub System.out.println("greet to"+name+"......"); } @Override public void serverTo(String name) { // TODO Auto-generated method stub System.out.println("serving "+name+"......"); } }
创建前置增强
package advice; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class GreetingBeforeAdvice implements MethodBeforeAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { // TODO Auto-generated method stub //arg0标识目标方法,arg1标识目标方法的参数值,arg2标识目标实例 System.out.println("====="+arg0.getName()+"====="); String clientName = (String) arg1[0]; System.out.println("How are you!"+clientName+"."); System.out.println("===="+arg2.getClass().getName()+"===="); } }
设置前置增强
package advice; import org.springframework.aop.framework.ProxyFactory; public class TestBeforeAdvice { public static void main(String[] args){ //创建目标实例 NaiveWaiter waiter = new NaiveWaiter(); //创建增强实例 GreetingBeforeAdvice advice = new GreetingBeforeAdvice(); //创建代理工厂 ProxyFactory factory = new ProxyFactory(); //设置代理目标 factory.setTarget(waiter); //为代理类添加增强 factory.addAdvice(advice); //生成代理实例 Waiter proxy = (Waiter) factory.getProxy(); proxy.greetTo("JSON"); proxy.serverTo("JSON"); } }
Spring配置前置增强实例:
application配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="beforeadvice"/> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="beforeadvice.Waiter" p:interceptorNames="greetingBeforeAdvice" p:target-ref="naiveWaiter" /> </beans>
设置前置增强
package beforeadvice; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestSpringBefore { public static void main(String[] args){ String path = "application.xml"; ApplicationContext ap = new ClassPathXmlApplicationContext(path); Waiter waiter = (Waiter) ap.getBean("waiter"); waiter.greetTo("JACK"); waiter.serverTo("JACK"); } }
后置增强
后置增强=连接点后+增强,后置增强是将在方法后织入增强,后置增强的实现类为AfterReturningAdvice。
前置增强的过程:1、创建代理工厂;2、创建目标类,也就是需要织入增强的类;3、通过AfterReturningAdvice生成增强类;4、将增强类和目标类添加到代理工厂;5、生成目标代理。
实例:
创建后置增强类
package advice.after; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class GreetingAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { // TODO Auto-generated method stub System.out.println("please enjoy yourself!"); } }
设置后置增强
package advice.after; import org.springframework.aop.framework.ProxyFactory; import com.sun.org.glassfish.external.statistics.Statistic; import advice.before.GreetingBeforeAdvice; import advice.before.NaiveWaiter; import advice.before.Waiter; public class TestAfterAdvice { public static void main(String[] args){ //创建目标实例 NaiveWaiter waiter = new NaiveWaiter(); //创建增强实例 GreetingAfterAdvice advice = new GreetingAfterAdvice(); //创建代理工厂 ProxyFactory factory = new ProxyFactory(); //设置代理目标 factory.setTarget(waiter); //为代理类添加增强 factory.addAdvice(advice); //生成代理实例 Waiter proxy = (Waiter) factory.getProxy(); proxy.greetTo("JSON"); proxy.serverTo("JSON"); } }
Spring配置后置增强实例:
application配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="advice"/> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="advice.before.Waiter" p:target-ref="naiveWaiter" > <property name="interceptorNames"> <list> <value>greetingBeforeAdvice</value> <value>after</value> </list> </property> </bean> </beans>
设置后置增强
package advice.before; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestSpringBefore { public static void main(String[] args){ String path = "application.xml"; ApplicationContext ap = new ClassPathXmlApplicationContext(path); Waiter waiter = (Waiter) ap.getBean("waiter"); waiter.greetTo("JACK"); waiter.serverTo("JACK"); } }
环绕增强
环绕增强=连接点前后+增强,在方法的前后都会织入增强,环绕增强的实现类为MethodInterceptor。
环绕增强过程:1、创建代理工厂;2、创建目标类,也就是需要织入增强的类;3、通过AfterReturningAdvice生成增强类;4、将增强类和目标类添加到代理工厂;5、生成目标代理。
Spring配置环绕增强实例:
定义增强类
package advice.interceptor; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.stereotype.Component; @Component("interceptor") public class GreetingInterceptor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation arg0) throws Throwable { // TODO Auto-generated method stub //目标方法入参 Object[] args = arg0.getArguments(); String str = (String) args[0]; System.out.println(str+"先生,你好!"); //执行目标方法 Object object = arg0.proceed(); System.out.println(str+"先生,有什么帮忙的?"); return object; } }
设置Spring配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <context:component-scan base-package="advice"/> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="advice.before.Waiter" p:target-ref="naiveWaiter" > <property name="interceptorNames"> <list> <value>greetingBeforeAdvice</value> <value>after</value> <value>interceptor</value> </list> </property> </bean> </beans>
设置环绕增强
package advice.before; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestSpringBefore { public static void main(String[] args){ String path = "application.xml"; ApplicationContext ap = new ClassPathXmlApplicationContext(path); Waiter waiter = (Waiter) ap.getBean("waiter"); waiter.greetTo("JACK"); waiter.serverTo("JACK"); } }
异常抛出增强
异常抛出增强=连接点异常后+增强,在异常后会织入增强,异常抛出增强的实现类为ThrowsAdvice。
异常抛出增强过程:1、创建代理工厂;2、创建目标类,也就是需要织入增强的类;3、通过ThrowsAdvice生成增强类;4、将增强类和目标类添加到代理工厂;5、生成目标代理。
Spring配置异常增强实例:
创建目标类
package advice.throwsadvice; import java.sql.SQLException; import org.springframework.stereotype.Component; @Component public class ForumService { public void removeForum(){ throw new RuntimeException("运行异常........."); } public void updateForum() throws SQLException{ throw new SQLException("数据库更新异常.........."); } }
创建异常增强类
package advice.throwsadvice; import java.lang.reflect.Method; import java.sql.SQLException; import java.util.concurrent.Executor; import org.springframework.aop.ThrowsAdvice; import org.springframework.stereotype.Component; @Component public class TransactionThrows implements ThrowsAdvice{ public void afterThrowing(Method method,Object[] objects, Object target, RuntimeException exception){ System.out.println("操作报错========"+"RuntimeException"); } public void afterThrowing(Method method,Object[] objects, Object target, SQLException exception){ System.out.println("操作报错========"+"SQLException"); } }
Spring配置异常增强
<bean id="forum" class="org.springframework.aop.framework.ProxyFactoryBean" p:target-ref="forumService"> <property name="interceptorNames"> <value> transactionThrows </value> </property> </bean>
引介增强
引介增强只是对目标类添加属性和方法。
创建切面
增强只是对每个类中的所有方法都要织入,没有条件限制。切面可以定位到目标类和目标方法进行增强的织入。
切点类型
-
-
- 静态方法切点:StaticMethodMatcherPointcut类过滤接入点的类和方法。
- 动态方法切点:DynamicMethodMatcherPointcut类在每次运行程序时都要过滤接入点的类和方法。
- 注解切点
- 表达式切点
- 流程切点
- 复合切点
-
切面类型
-
-
- Advisor:代表一般切面。
- PoincutAdvisor:代表具有切入点的切面。
- IntroductionAdvisor:代表引介切面。
-
PointcutAdvisor
PointcutAdvisor共有6个具体实现类
-
- DefaultPointcutAdvisor:主要通过Pointcut和Advice构成一个切面,例如动态切面、流程切面、复合切面等切面的构成。
- StaticMethodMatcherPointcutAdvisor:用于设置静态切面
- NameMethodMatcherPointcutAdvisor:按照方法名定义切点的切面。
- RegexMethodMatcherPointcutAdvisor:通过正则表达式匹配方法名定义切点的切面。
- AspectJExpressionPointcutAdvisor
- AspectJPointcutAdvisor
1、静态普通方法名匹配切面
该切面会通过类名和方法名对增强进行准确的织入。StaticMethodMatcherPointcutAdvisor方法对目标类和方法进行过滤。
创建过程:1、创建目标类和方法;2、通过StaticMethodMatcherPointcutAdvisor创建切面对接入点进行过滤;3、创建增强;4、将增强注入切面;5、将目标类、切面加入代理。
Waiter.java文件
package advisor; import org.springframework.stereotype.Component; @Component("waiterTarget") public class Waiter { public void greetTo(String name){ System.out.println("waiter greet to "+name+"......"); } public void serveTo(String name){ System.out.println("waiter serving to "+name+"....."); } }
Seller.java文件
package advisor; import org.springframework.stereotype.Component; @Component("sellerTarget") public class Seller { public void greetTo(String name){ System.out.println("seller greet to "+name+"......"); } public void serveTo(String name){ System.out.println("seller serving to "+name+"....."); } }
创建增强类
package advice.before; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.stereotype.Component; @Component public class GreetingBeforeAdvice implements MethodBeforeAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { // TODO Auto-generated method stub //arg0标识目标方法,arg1标识目标方法的参数值,arg2标识目标实例 System.out.println("====="+arg0.getName()+"====="); String clientName = (String) arg1[0]; System.out.println("How are you!"+clientName+"."); System.out.println("===="+arg2.getClass().getName()+"===="); } }
创建切面
package advisor.staticmethod; import java.lang.reflect.Method; import org.springframework.aop.ClassFilter; import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; import advisor.Waiter; public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor{ @Override public boolean matches(Method method, Class<?> arg1) { // TODO Auto-generated method stub System.out.println("开始过滤方法======="); return "greetTo".equals(method.getName()); } @Override public ClassFilter getClassFilter(){ return new ClassFilter() { public boolean matches(Class clazz) { // TODO Auto-generated method stub System.out.println("开始过滤类======="); return Waiter.class.isAssignableFrom(clazz); } }; } }
Spring配置文件
<!-- 向切面注入前置增强 --> <bean id="greetingAdvisor" class="advisor.staticmethod.GreetingAdvisor" p:advice-ref="greetingBeforeAdvice"/> <!-- 定义公共配置信息 --> <bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true"/> <bean id="waiter1" parent="parent" p:target-ref="waiterTarget"/> <bean id="seller" parent="parent" p:target-ref="sellerTarget"/>
测试
package advisor; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAdvisor { public static void main(String[] args){ String path = "application.xml"; ApplicationContext ap = new ClassPathXmlApplicationContext(path); Waiter waiter = (Waiter) ap.getBean("waiter1"); waiter.greetTo("李小龙"); } }
2、静态正则表达式方法匹配切面
该切面会通过类名和方法名对增强进行准确的织入。RegexMethodMatcherPointcutAdvisor方法对目标类和方法进行过滤。
创建过程:1、创建目标类和方法;2、通过RegexMethodMatcherPointcutAdvisor创建切面对接入点进行过滤;3、创建增强;4、将目标类、切面和增强加入代理。
3、动态切面
动态切点在每次执行时都要进行目标类和目标方法的检查,虽然这会对服务性能造成影响,因此在进行动态检查时,首先进行静态检查,检查通过后进行动态检查。动态切面使用的类为DynamicMethodMatcherPointcut。
创建过程:1、创建目标类和方法;2、通过DynamicMethodMatcherPointcut创建动态切面;3、创建增强;4、将增强和动态切面注入默认切面;5、将目标类、切面注入代理。
创建动态切点类
package advisor.dynamic; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.springframework.aop.ClassFilter; import org.springframework.aop.support.DynamicMethodMatcherPointcut; import advisor.Waiter; public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut{ private static List<String> list = new ArrayList<String>(); static{ list.add("李小刚"); } public boolean matches(Method method, java.lang.Class<?> targetClass) { System.out.println("对方法进行静态过滤========="); return "serveTo".equals(method.getName()); } @Override public boolean matches(Method arg0, Class<?> arg1, Object... arg2) { // TODO Auto-generated method stub System.out.println("对方法进行动态过滤================="); String clientname = (String) arg2[0]; return list.contains(clientname); } public ClassFilter getClassFilter(){ System.out.println("对类进行过滤==============="); return new ClassFilter() { @Override public boolean matches(Class<?> arg0) { // TODO Auto-generated method stub return Waiter.class.isAssignableFrom(arg0); } }; } }
Spring进行配置动态切面
<bean id="parent1" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="dynamicAdvisor" p:proxyTargetClass="true"/> <bean id="waiter2" parent="parent1" p:target-ref="waiterTarget"/>
测试
package advisor; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAdvisor { public static void main(String[] args){ String path = "application.xml"; ApplicationContext ap = new ClassPathXmlApplicationContext(path); Waiter waiter = (Waiter) ap.getBean("waiter2"); waiter.serveTo("李小刚"); } }
4、流程切面
流程切面与动态切面相似,但是效率较低。流程切面主要有DefaultPointcutAdvisor和ControlFlowPointcut实现。
创建过程:1、创建目标类和方法;2、创建增强;3、ControlFolwPointcut类注入目标类和方法生成切点;4、将切点和增强注入普通切面;5、将切面和目标方法注入代理;
Spring文件配置
<!-- 设置流程切点 --> <bean id="contrlflowpointcut" class="org.springframework.aop.support.CrontrolFolwPointcut"> <constructor-arg type="java.lang.Class" value=""/> <constructor-arg type="java.lang.String" value="service"/> </bean> <!-- 设置流程切面 --> <bean id="controlflowadvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="pointcut"> <ref bean="contrlflowpointcut"/> </property> <property name="advice"> <bean class="advice.before.GreetingBeforeAdvice"/> </property> </bean> <!-- 设置目标代理类 --> <bean id="parent2" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="controlflowadvisor" p:proxyTargetClass="true"/> <bean id="waiter3" parent="parent2" p:target-ref="waiterTarget"/>
需要织入增强的类
package advisor.controlfolw; import advisor.Waiter; public class WaiterDelegate { private Waiter waiter; public Waiter getWaiter() { return waiter; } public void setWaiter(Waiter waiter) { this.waiter = waiter; } public void service(String clientName){ waiter.greetTo(clientName); waiter.serveTo(clientName); } }
测试
package advisor; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import advisor.controlfolw.WaiterDelegate; public class TestAdvisor { public static void main(String[] args){ String path = "application.xml"; ApplicationContext ap = new ClassPathXmlApplicationContext(path); Waiter waiter = (Waiter) ap.getBean("waiter3"); WaiterDelegate delegate = new WaiterDelegate(); delegate.setWaiter(waiter); delegate.service("小刚"); } }
5、复合切点切面
复合切点切面是将多个切点添加到复合切点对象中,生成复合切点的类为ComposablePointcut类。复合切点可以由两种方法实现,1、insertsection方法实现切点交集;2、union方法实现切点并集。
创建过程:1、通过ComposablePointcut创建复合切点,将其他类型的切点加入其中。2、将复合切点和增强注入切面Bean中;3、将切面注入代理Bean。
创建复合切点类
package advisor.composable; import org.springframework.aop.Pointcut; import org.springframework.aop.support.ComposablePointcut; import org.springframework.aop.support.ControlFlowPointcut; import org.springframework.aop.support.NameMatchMethodPointcut; import org.springframework.stereotype.Component; import advisor.controlfolw.WaiterDelegate; @Component("componsable") public class GreetingComposablePointcut { public ComposablePointcut getComposablePointcut(){ ComposablePointcut pointcut = new ComposablePointcut(); Pointcut pc = new ControlFlowPointcut(WaiterDelegate.class, "service"); NameMatchMethodPointcut mPointcut = new NameMatchMethodPointcut(); mPointcut.addMethodName("greetTo"); return pointcut.intersection(pc).intersection(mPointcut); } }
Spring配置
<!-- 创建复合切面 --> <bean id="composableadvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="pointcut"> <ref bean="#componsable.composablePointcut"/> </property> <property name="advice"> <bean class="advice.before.GreetingBeforeAdvice"/> </property> </bean> <!-- 创建目标代理 --> <bean id="parent3" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="composableadvisor" p:proxyTargetClass="true"/> <bean id="waiter4" parent="parent3" p:target-ref="waiterTarget"/>
以上是关于Spring AOP-----------基础的主要内容,如果未能解决你的问题,请参考以下文章