与大多数技术一样, AOP 已经形成了自己的术语。描述切面的常用术语有通知(advice)、切点(pointcut)和连接点(join point)。从今天开始,我们对spring的切面编程做一个总结。她们都是你漫漫长路上,只配错过的好姑娘。
spring中的aop
spring的切面可以应用以下的5种类型的通知:
- 前置通知(Before):在目标方法被调用之前调用通知功能;
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
- 返回通知(After-returning):在目标方法成功执行之后调用通知;
- 异常通知(After-throwing):在目标方法抛出异常后调用通知;
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
对于spring中aop的支持,主要分为@AspectJ 注解驱动的切面和基于xml的spring的配置。以下我们对这两种配置做一个简单的了解。测试的代码目录如下:
以后可能对于spring的关于aop学习,这个目录可能会添加代码。application-xml.xml是学习xml配置的,application-aop.xml是学习@Aspectj注解配置的。
springaop的xml配置方式
一、我们的application-xml.xml文件内容如下:
<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 id="myService" class="com.linux.huhx.business.service.MyAspectService3"/> <bean id="myAspect" class="com.linux.huhx.aspect.XmlUserfulAspect"/> <aop:config> <aop:aspect id="xmlAspect1" ref="myAspect"> <aop:pointcut id="businessService" expression="execution(* com.linux.huhx.business.service.MyAspectService3.*())"/> <aop:before method="beforeExecute" pointcut-ref="businessService"/> <aop:after method="afterExecute" pointcut-ref="businessService"/> </aop:aspect> </aop:config> </beans>
二、我们的切面类XmlUserfulAspect如下:
package com.linux.huhx.aspect; /** * @Author: huhx * @Date: 2017-12-15 下午 12:31 * @Desc: 切面类 */ public class XmlUserfulAspect { public void beforeExecute() { System.out.println("before execute."); } public void afterExecute() { System.out.println("after execute."); } }
三、我们简单的定义一个应用切面的服务类
package com.linux.huhx.business.service; /** * @Author: huhx * @Date: 2017-12-15 下午 12:28 */ public class MyAspectService3 { public void serviceMethod() { System.out.println("my aspect service1 method."); } }
四、在main的类中我们对上述的切面进行测试
package com.linux.huhx.main; import com.linux.huhx.business.service.MyAspectService3; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @Author: huhx * @Date: 2017-12-15 下午 12:32 * @Desc: 基于xml配置的aop测试主体类 */ public class XmlServiceMain { private ApplicationContext context = null; @Before public void initApplicationContext() { context = new ClassPathXmlApplicationContext("application-xml.xml"); } @Test public void aspectServiceTest_1() { MyAspectService3 myAspectService1 = context.getBean("myService", MyAspectService3.class); myAspectService1.serviceMethod(); } }
打印的结果如下:
before execute.
my aspect service1 method.
after execute.
springaop中关于注解的方式
这里面设计的代码比较多,主要是为了测试不同的知识点。这里全部贴出代码,后续再做整理。后续我们对这两种的配置方式做一个比较细致的过程讲解。使用aspectj,我们需要在pom.xml文件中添加依赖:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.11</version> </dependency>
一、application-aop.xml的文件内容如下
<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"> <aop:aspectj-autoproxy/> <bean id="myService1" class="com.linux.huhx.business.service.MyAspectService1"/> <bean id="myService2" class="com.linux.huhx.business.service.MyAspectService2"/> <!--declare an aspect--> <bean id="myAspect" class="com.linux.huhx.aspect.NotVeryUsefulAspect"/> <bean id="myAspect1" class="com.linux.huhx.aspect.LittleUserfulAspect"/> </beans>
二、两个测试切面的服务类如下:
- MyAspectService1:这里面主要测试切面的5种类型的通知。
package com.linux.huhx.business.service; import java.io.FileNotFoundException; /** * @Author: huhx * @Date: 2017-12-15 上午 10:08 * @Desc: 一个简单的测试aspect的实类 */ public class MyAspectService1 { public void serviceMethod() { System.out.println("myaspect service1 method."); } public String returnServiceMethod() { return "return huhx."; } public String throwExceptionMethod() { System.out.println("throw exception method."); try { throw new FileNotFoundException("not found class."); } catch (FileNotFoundException e) { e.printStackTrace(); } return "hello world"; } public String aroundServiceMethod1() { System.out.println("around service method."); return "huhx"; } }
- MyAspectService2.java:这里面测试切面传递参数。
package com.linux.huhx.business.service; import java.util.Map; /** * @Author: huhx * @Date: 2017-12-15 上午 11:17 */ public class MyAspectService2 { public void serviceMethod_1(Map<String, String> map) { System.out.println("service method." + map); } }
三、两个切面的类如下
- NotVeryUsefulAspect:是针对于上述的MyAspectService1类的,为了测试5种通知类型。
package com.linux.huhx.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; /** * @Author: huhx * @Date: 2017-12-15 上午 9:51 * @Desc: 定义一个aspect */ @Aspect public class NotVeryUsefulAspect { private static final String pointCutString = "execution(* com.linux.huhx.business.service.MyAspectService1.*())"; @Before(pointCutString) public void beforeExecute() { System.out.println("before advice."); } @After(pointCutString) public void afterExecute() { System.out.println("after advice."); } @AfterReturning(value = pointCutString, returning = "retVal") public void afterReturingExecute1(String retVal) { System.out.println("after throwing " + retVal); } @AfterThrowing(value = pointCutString, throwing = "exception") public void afterThrowingExecute1(Throwable exception) { System.out.println("throwing in advice show message: " + exception.getMessage()); } @Around(value = pointCutString) public void arundExecute1(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("before around."); System.out.println(pjp.proceed()); System.out.println("after around."); } }
- LittleUserfulAspect:是对应于MyAspectService2类的,为了测试切面中参数的传递。
package com.linux.huhx.aspect; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import java.util.Map; /** * @Author: huhx * @Date: 2017-12-15 上午 11:16 * @Desc: 定义一个切面 */ @Aspect public class LittleUserfulAspect { @Pointcut("execution(* com.linux.huhx.business.service.MyAspectService2.*(..)) && args(map,..)") public void anyMethod(Map<String, String> map) {} @Before(value = "anyMethod(map)") public void beforeExecute(Map map) { System.out.println("before execute." + map); } }
四、我们的测试主体类ServiceMain
package com.linux.huhx.main; import com.linux.huhx.business.service.MyAspectService1; import com.linux.huhx.business.service.MyAspectService2; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.HashMap; import java.util.Map; /** * @Author: huhx * @Date: 2017-12-15 上午 10:13 * @Desc: 测试的main类 */ public class ServiceMain { private ApplicationContext context = null; @Before public void initApplicationContext() { context = new ClassPathXmlApplicationContext("application-aop.xml"); } @Test public void aspectServiceTest_1() { MyAspectService1 myAspectService1 = context.getBean("myService1", MyAspectService1.class); myAspectService1.serviceMethod(); } @Test public void aspectServiceTest_2() { MyAspectService1 myAspectService1 = context.getBean("myService1", MyAspectService1.class); myAspectService1.returnServiceMethod(); } @Test public void aspectServiceTest_3() { MyAspectService1 myAspectService1 = context.getBean("myService1", MyAspectService1.class); myAspectService1.throwExceptionMethod(); } @Test public void aspectServiceTest_4() { MyAspectService1 myAspectService1 = context.getBean("myService1", MyAspectService1.class); myAspectService1.aroundServiceMethod1(); } /* 其它的切面实现类 */ @Test public void aspectServiceTest_5() { MyAspectService2 myAspectService2 = context.getBean("myService2", MyAspectService2.class); Map<String, String> dataMap = new HashMap<>(); dataMap.put("username", "linux"); dataMap.put("password", "12345"); myAspectService2.serviceMethod_1(dataMap); } }