原理
AOP 即 Aspect Oriented Program 面向切面编程
首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
然后把切面功能和核心业务功能 “编织” 在一起,这就叫AOP
常用场景:
切面一般对如下内容进行封装,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。
- 事务
- 权限处理
- 日志
- 性能检测
- 异常处理
示例工程:

代码:
XML配置AOP
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"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="productservice" class="com.how2java.service.ProductService"/><bean id="loggerAspect" class="com.how2java.aspect.LoggerAspect"/><bean id="diy" class="com.how2java.aspect.DiyAspect"/><aop:config><aop:pointcut id="loggerCutpoint"expression="execution(* com.how2java.service.ProductService.*(..)) "/><aop:aspect id="logAspect" ref="loggerAspect"><aop:around pointcut-ref="loggerCutpoint" method="log" /><aop:around pointcut-ref="loggerCutpoint" method="performance" /></aop:aspect><aop:aspect ref="diy"><aop:pointcut id="point" expression="execution(* com.how2java.service.ProductService.*(..))"/><aop:before method="before" pointcut-ref="point"/><aop:after method="after" pointcut-ref="point"/></aop:aspect></aop:config></beans>
DiyAspect.java
package com.how2java.aspect;public class DiyAspect {public void before() {System.out.println("方法执行前");}public void after() {System.out.println("方法执行后");}}
LoggerAspect.java
package com.how2java.aspect;import java.util.Date;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 performance(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.nanoTime(); // 获取开始时间System.out.println(new Date().toString());Object object = joinPoint.proceed();long endTime = System.nanoTime(); // 获取结束时间System.out.println(new Date().toString());System.out.println("程序运行时间: " + (endTime - startTime) + "ns");return object;}}
ProductService.java
package com.how2java.service;import org.springframework.stereotype.Component;public class ProductService {public void doSomeService(){System.out.println("doSomeService");}public void doSomeOtherService() {System.out.println("doSomeOtherService");}}
TestSpring.java
package com.how2java.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.how2java.service.ProductService;public class TestSpring {public static void main(String[] args) {// TODO Auto-generated method stubApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");ProductService s = (ProductService) context.getBean("productservice");s.doSomeService();s.doSomeOtherService();}}
注解配置AOP
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"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="com.how2java.aspect"/><context:component-scan base-package="com.how2java.service"/><aop:aspectj-autoproxy/></beans>
DiyAspect.java
package com.how2java.aspect;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;@Aspect@Componentpublic class DiyAspect {@Before(value = "execution(* com.how2java.service.ProductService.*(..))")public void before() {System.out.println("方法执行前");}@After(value = "execution(* com.how2java.service.ProductService.*(..))")public void after() {System.out.println("方法执行后");}}
LoggerAspect.java
package com.how2java.aspect;import java.util.Date;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;@Aspect@Componentpublic class LoggerAspect {@Around(value = "execution(* com.how2java.service.ProductService.*(..))")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;}@Around(value = "execution(* com.how2java.service.ProductService.*(..))")public Object performance(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.nanoTime(); // 获取开始时间System.out.println(new Date().toString());Object object = joinPoint.proceed();long endTime = System.nanoTime(); // 获取结束时间System.out.println(new Date().toString());System.out.println("程序运行时间: " + (endTime - startTime) + "ns");return object;}}
ProductService.java
package com.how2java.service;import org.springframework.stereotype.Component;@Component("productservice")public class ProductService {public void doSomeService(){System.out.println("doSomeService");}public void doSomeOtherService() {System.out.println("doSomeOtherService");}}
TestSpring.java
package com.how2java.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.how2java.service.ProductService;public class TestSpring {public static void main(String[] args) {// TODO Auto-generated method stubApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");ProductService s = (ProductService) context.getBean("productservice");s.doSomeService();s.doSomeOtherService();}}
要点:
1.Aop在xml要配置
xmlns:aop=”http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xs
分别对应applicationContext.xml第五行、第十四十五行。
2.Advice主要类型:
- @Before:该注解标注的方法在业务模块代码执行之前执行,其不能阻止业务模块的执行,除非抛出异常;
- @AfterReturning:该注解标注的方法在业务模块代码执行之后执行;
- @AfterThrowing:该注解标注的方法在业务模块抛出指定异常后执行;
- @After:该注解标注的方法在所有的Advice执行完成后执行,无论业务模块是否抛出异常,类似于finally的作用;
- @Around:该注解功能最为强大,其所标注的方法用于编写包裹业务模块执行的代码,其可以传入一个ProceedingJoinPoint用于调用业务模块的代码,无论是调用前逻辑还是调用后逻辑,都可以在该方法中编写,甚至其可以根据一定的条件而阻断业务模块的调用;
- @DeclareParents:其是一种Introduction类型的模型,在属性声明上使用,主要用于为指定的业务模块添加新的接口和相应的实现。
@Aspect:严格来说,其不属于一种Advice,该注解主要用在类声明上,指明当前类是一个组织了切面逻辑的类,并且该注解中可以指定当前类是何种实例化方式,主要有三种:singleton、perthis和pertarget,具体的使用方式后面会进行讲解。
这里需要说明的是,@Before是业务逻辑执行前执行,与其对应的是@AfterReturning,而不是@After,@After是所有的切面逻辑执行完之后才会执行,无论是否抛出异常。
3.在aop中execution的写法规则
执行表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 ,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 () 匹配了一个接受一个任何类型的参数的方法。 模式 (,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。
一些常见切入点表达式的例子。
execution(public (..)) 任意公共方法的执行;
execution( set(..)) 任何一个以“set”开始的方法的执行;
execution( com.xyz.service.AccountService.(..)) AccountService接口的任意方法的执行;
execution( com.xyz.service..(..)) 定义在service包里的任意方法的执行;
execution( com.xyz.service...(..)) 定义在service包或者子包里的任意方法的执行;4.作用同@Component的注解
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
