Spring AOP概念:
AOP:Aspect Oriented Program ---------面向切面编程。
- 功能:核心业务功能(如登录,增删数据等)和周边功能(日志等),周边功能在Spring的面向切面编程的AOP思想里,被定义为切面。
- 核心业务和切面功能分别独立开发,然后有选择性的把切面功能和核心业务功能“编织”在一起,这就是AOP。
AOP项目
- 项目设计
核心功能:ProductService和ProductService1
辅助功能:日志输出,性能统计
- 项目开始
1,**就像一般的Java类,编写核心功能类。
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
public void doCheck(){
System.out.println("Do check");
}
}
2,准备日志和性能统计切面**
例如日志切面:
示例代码如下:
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
//与某个核心功能编织后,用于执行性核心功能
//所以,此日志切面功能是:在调用核心功能前后分别打印日志文件函数名字
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
3,编写applicationContext.xml文件
- 声明业务对象(按照一般类对象声明)
<bean name="s" class="com.moon.service.ProductService">
</bean>
- 声明日志切面(注意是bean id=xx,且不需要结尾)
<!-- 控制反转 切面类 -->
<bean id="loggerAspect" class="com.moon.aspect.LoggerAspect"/>
<!-- 控制反转 性能统计的切面类 -->
<bean id="performerAspect" class="com.moon.aspect.PerformerAspect"/>
- 在aop:config和</aop:config>中指定核心功能和切面业务,并把他们编织起来
(1)设置核心功能
<aop:config>
<!--不同的切入点要分别写在不同的aop:config里面-->
<!-- 设置切入点(核心功能)的作用对象和id -->
<aop:pointcut id="Cutpoint"
expression="execution(* com.moon.service.ProductService.*(..)) "/>
//执行所有的核心功能ProductService类里面的所有函数
//指定辅助功能
</aop:config>
execution(* com.moon.service.ProductService.*(…))函数:
# *表示返回任意类型
# com.moon.service.ProductService.*是指以包名com.moon.service下类 ProductService的任意方法
# (…)表示任意数量和类型
(2)指定辅助功能
一个辅助功能与多个核心功能编织,切面aspect id要不同,但是注入同样对象
<!-- 设置切面的id,注入对象-->
<aop:aspect id="logAspect" ref="loggerAspect">
<!--该切面中的log方法会被以环绕“around”方式放置于Cutpoint切入点 -->
<aop:around pointcut-ref="Cutpoint" method="log"/>
<aop:around pointcut-ref="Cutpoint" method="log1"/>
</aop:aspect>
<!--该切面中的spend方法会被以环绕“around”方式放置于Cutpoint切入点 -->
<aop:aspect id="performAspect" ref="performerAspect">
<aop:around pointcut-ref="Cutpoint" method="spend"/>
</aop:aspect>
<aop:config>
<aop:pointcut id="cutpoint1" expression="execution(* com.moon.service.ProductService1.*(..)) "/>
<aop:aspect id="logAspect1" ref="loggerAspect">
<aop:around pointcut-ref="cutpoint1" method="log"/>
<aop:around pointcut-ref="cutpoint1" method="log1"/>
</aop:aspect>
</aop:config>
4,编写测试类
只需定义核心功能的对象,并调用其方法即可,被调用的方法将会被切面类中的方法按照顺序环绕。
ProductService s = (ProductService) context.getBean("s");
s.doSomeService();
s.doCheck();
具体代码
ProductService.java
package com.moon.service;
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
public void doCheck(){
System.out.println("Do check");
}
}
ProductService1.java
package com.moon.service;
public class ProductService1 {
public void show(){
System.out.println("this is another a service");
}
}
LoggerAspect.java
package com.moon.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
public Object log1(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my log0:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("my log1:" + joinPoint.getSignature().getName());
return object;
}
}
PerformerAspect.java
package com.moon.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import java.util.Date;
public class PerformerAspect {
//环绕式切入
public Object spend(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("开始于" + new Date(start));
Object object = proceedingJoinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("结束于" + new Date(end));
return object;
}
}
TestSpring.java
package com.moon.test;
import com.moon.service.ProductService;
import com.moon.service.ProductService1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
ProductService s = (ProductService) context.getBean("s");
s.doSomeService();
s.doCheck();
ProductService1 s1 = (ProductService1) context.getBean("s1");
s1.show();
}
}
applicationContext.xml
<?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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean name="s" class="com.moon.service.ProductService">
</bean>
<bean name="s1" class="com.moon.service.ProductService1">
</bean>
<!-- 控制反转 切面类 -->
<bean id="loggerAspect" class="com.moon.aspect.LoggerAspect"/>
<!-- 控制反转 性能统计的切面类 -->
<bean id="performerAspect" class="com.moon.aspect.PerformerAspect"/>
<aop:config>
<!-- 设置切入点的作用对象和id -->
<aop:pointcut id="Cutpoint"
expression=
"execution(* com.moon.service.ProductService.*(..)) "/>
<!-- 设置切面的id,以及该切面中的log方法会被以环绕“around”方式放置于loggerCutpoint切入点 -->
<aop:aspect id="logAspect" ref="loggerAspect">
<aop:around pointcut-ref="Cutpoint" method="log"/>
<aop:around pointcut-ref="Cutpoint" method="log1"/>
</aop:aspect>
<!-- bean时一个id,aop时一个id -->
<aop:aspect id="performAspect" ref="performerAspect">
<aop:around pointcut-ref="Cutpoint" method="spend"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:pointcut id="cutpoint1" expression="execution(* com.moon.service.ProductService1.*(..)) "/>
<aop:aspect id="logAspect1" ref="loggerAspect">
<aop:around pointcut-ref="cutpoint1" method="log"/>
<aop:around pointcut-ref="cutpoint1" method="log1"/>
</aop:aspect>
</aop:config>
</beans>
运行结果:
一个切面可以编织到多个切入点(核心功能),可以通过调用核心功能方法来实现编织,但是一个切面编织到多个切入点需要在aop:aspect里面设置不同的切面id。
多个切面可以与一个切入点编织,只要在一个切入点设置里面分别声明切面id以及其切入点和切面方法。