概念
AOP(Aspect Oriented Programming),即面向切面编程(也叫面向方面编程,面向方法编程)。其主要作用是,在不修改源代码的情况下给某个或者一组操作添加额外的功能。像日志记录,事务处理,权限控制等功能,都可以用AOP来“优雅”地实现,使这些额外功能和真正的业务逻辑分离开来,软件的结构将更加清晰。AOP是OOP的一个强有力的补充。
术语
AOP的术语不太直观,Spring文档中也没有给一个确切的定义,所以重在理解。
-
Join Point(连接点): 所谓的连接点就是被拦截到的点,spring中,这些点指的就是方法(通俗来讲就是起作用的那个方法)。spring中只支持方法类型的连接点,事实上join point还可以是field或类构造器。
- Pointcut(切入点):用来指定join point(通俗来讲就是描述(定义)的一组符合某个条件的join point)。通常使用pointcut表达式来限定joint point,
Spring默认使用AspectJ pointcut expression language。Pointcut通过pointcut expression来描述,有若干种限定词。由于Pointcut的定义在Spring文档7.2.3 Declaring a pointcut中写得比较详细,所以在此不再赘述。
eg: execution(* com.tech.service.impl..*.*(..)) 含义:执行([任何]返回类型 包名[..代表所有子包][*.*所有类的所有方法](..[任何参数]))
- Advice(通知):是指拦截到join point在特定的时刻执行的操作,Advice有以下几种不同类型:(通俗地来讲就是起作用的内容和时间点)
- Before advice: 执行在join point之前的advice,但是它不能阻止joint point的执行流程,除非抛出了一个异常(exception)。
- After returning advice: 执行在join point这个方法返回之后的advice。
- After throwing advice: 执行在join point抛出异常之后的advice。
- After(finally) advice: 执行在join point返回之后或者抛出异常之后的advice,通常用来释放所使用的资源。
- Around advice: 执行在join point这个方法执行之前与之后的advice。
- Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期动态的给对象增加方法或者属性。
- Target object: Advice起作用的那个对象,代理的对象。
- AOP proxy:为实现AOP所生成的代理。在Spring中有两种方式生成代理:JDK代理和CGLIB代理。
- Aspect: 组合了Pointcut与Advice,在Spring中有时候也称为Advisor。某些资料说Advisor是一种特殊的Aspect,其区别是Advisor只能包含一对pointcut和advice,但是aspect可以包含多对。AOP中的aspect可以类比于OOP中的class。
- Weaving:将Advice织入join point的这个过程。
织入器通过在切面中pointcut(切入点定义)来搜索目标(被代理类)的JoinPoint(切入点),然后把要切入的逻辑(Advice)织入到目标对象里,生成代理类。
两种代理
Spring AOP是基于代理机制的,Spring AOP通过JDK Proxy和CGLIB Proxy两种方法实现代理。
- 如果target object没有实现任何接口,那么Spring将使用CGLIB来实现代理。CGLIB是一个开源项目,它是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
- 如果target object实现了一个以上的接口,那么Spring将使用JDK Proxy来实现代理,因为Spring默认使用的就是JDK Proxy,并且JDK Proxy是基于接口的。这也是Spring提倡的面向接口编程。当然,你也可以强制使用CGLIB来进行代理,但是这样可能会造成性能上的下降。
我们可以通过三种方式来使用Spring AOP,它们分别是:@Aspect-based(Annotation),Schema-based(XML),以及底层的Spring AOP API。
一、@Aspect-based (Annotation)
通过Annotaion(注解)实现AOP是最常用的方式。
1)配置
首先,我们应该在配置文件中增加对Annotation的支持。
假设我们的配置文件是classpath下的applicationContext.xml,添加如下片段:
<aop:aspectj-autoproxy />
2)业务逻辑类
假设我们有一个UserManager类,这个类负责处理业务逻辑。类的定义如下:
- public class UserManager {
- /*这个方法需要一个参数*/
- public void addUser(String user) {
- System.out.println("addUser(String str) method is executed!");
- }
- public void deleteUser() {
- System.out.println("deleteUser() method is executed!");
- }
- /*这个方法返回一个字符串*/
- public String getUser() {
- System.out.println("getUser() method is executed!");
- return "Hello";
- }
- /*这个方法抛出一个异常*/
- public void editUser() throws Exception {
- throw new Exception("something is wrong.");
- }
- }
这是一个很普通的Java对象,看不出任何Spring AOP的痕迹,这也是Spring低侵入式设计的体现。
3)切面(Aspect)类
为了给业务逻辑增加额外功能,我们需要定义一个切面类,切面类里包含了pointcut和advice。假设我们的切面类是ExampleAspect,代码如下:
- @Aspect
- public class ExampleAspect {
- @Pointcut("execution(* com.psjay.example.spring.aop.*.*(..))")
- public void aPointcut() {
- }
- @Before("aPointcut()")
- public void beforeAdvice() {
- System.out.println("before advice is executed!");
- }
- @AfterReturning(pointcut = "aPointcut()", returning = "r")
- public void afterReturningAdvice(String r) {
- if (r != null)
- System.out
- .println("after returning advice is executed! returning String is : "
- + r);
- }
- @After("aPointcut()")
- public void AfterAdvice() {
- System.out.println("after advice is executed!");
- }
- @After("aPointcut() && args(str)")
- public void AfterAdviceWithArg(String str) {
- System.out.println("after advice with arg is executed!arg is : " + str);
- }
- @AfterThrowing(pointcut = "aPointcut()", throwing = "e")
- public void afterThrowingAdvice(Exception e) {
- System.out
- .println("after throwing advice is executed!exception msg is : "
- + e.getMessage());
- }
- }
在基于annotation的Spring AOP中,@Aspect用来标注切面类。@Pointcut标注一个空的方法,用来代表一个pointcut,这个方法必须是public的。@Pointcut注解括号内是pointcut expression,例子中的表达式表示com.psjay.example.spring.aop的所有方法都是join point。而@Before,@After等注解对应着几种不同类型的Advice。被标注的方法就是一个Advice。@Advice注解括号内是一个pointcut。例子中的@afterReturningAdvice(),AfterAdviceWithArg()和afterThrowingAdvice()分别演示了Advice得到join point的返回值,Advice使用join point的参数,Advice使用join point抛出的异常对象几种操作。
不要忘了在Spring配置文件中配置以上两个类的“Bean”,这里就不贴出具体代码了。
4)测试类
测试类相对简单,就是从Spring中拿出bean演示AOP的结果。测试类代码如下:
- public class Test {
- public static void main(String[] args) {
- ApplicationContext ctx = new ClassPathXmlApplicationContext(
- "applicationContext.xml");
- UserManager um = ctx.getBean("userManager", UserManager.class);
- System.out.println("------ Case 1 --------");
- um.addUser("hey");
- System.out.println("------ Case 2 --------");
- try {
- um.editUser();
- } catch (Exception e) {
- }
- System.out.println("------ Case 3 --------");
- um.getUser();
- }
- }
测试结果:
- —— Case 1 ——–
- before advice is executed!
- addUser(String str) method is executed!
- after advice is executed!
- after advice with arg is executed!arg is : hey
- —— Case 2 ——–
- before advice is executed!
- after advice is executed!
- after throwing advice is executed!exception msg is : something is wrong.
- —— Case 3 ——–
- before advice is executed!
- getUser() method is executed!
- after returning advice is executed! returning String is : Hello
- after advice is executed!
可以看到,Advice已经在对应的join point上起作用了。
二、 Schema-based(XML)
除了使用Annotation,我们还可以使用XML来实现Spring AOP。使用XML来实现AOP只是将AOP的配置信息移到XML配置文件里。
1)业务类
- package com.tech.aop.service;
- public interface CustomerService {
- public String getName(Integer id);
- public void save(String name);
- public void update(Integer id, String name);
- }
- package com.tech.aop.service.impl;
- import com.tech.aop.service.CustomerService;
- public class CustomerServiceBean implements CustomerService {
- @Override
- public String getName(Integer id) {
- System.out.println("这是find方法");
- return "zhang";
- }
- @Override
- public void save(String name) {
- //throw new RuntimeException("例外通知");
- System.out.println("这是save方法");
- }
- @Override
- public void update(Integer personId, String name) {
- System.out.println("这是update方法");
- }
- }
2)切面(Aspect)类
- package com.tech.xml.aop;
- import org.aspectj.lang.ProceedingJoinPoint;
- /**
- * 切面
- *
- * @author ch
- *
- */
- public class MyInterceptor {
- public void doBefore() {
- System.out.println("前置通知");
- }
- public void doAfterReturning() {
- System.out.println("后置通知");
- }
- public void doAfter() {
- System.out.println("最终通知");
- }
- public void doAfterThrowing() {
- System.out.println("例外通知");
- }
- public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
- System.out.println("进入方法");
- Object result = pjp.proceed();
- System.out.println("退出 方法");
- return result;
- }
- }
3)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:p="http://www.springframework.org/schema/p"
- 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"
- default-lazy-init="false">
- <!-- 添加对 @AspectJ 注解的支持 -->
- <aop:aspectj-autoproxy />
- <!-- 业务类定义 -->
- <bean id="customerService" class="com.tech.aop.service.impl.CustomerServiceBean" />
- <!-- 切面(Aspect)类定义 -->
- <bean id="myInterceptor" class="com.tech.xml.aop.MyInterceptor"/>
- <!-- AOP配置 -->
- <aop:config>
- <!-- 配置切面类 -->
- <aop:aspect id="apt" ref="myInterceptor">
- <!-- 定义切入点(通过表达式对指定方法进行拦截) -->
- <aop:pointcut id="mypCut" expression="execution(* com.tech.aop.service.impl.CustomerServiceBean.*(..))"/>
- <!-- 定义advice(不同类型的通知) -->
- <aop:before method="doBefore" pointcut-ref="mypCut"/>
- <aop:after-returning method="doAfterReturning" pointcut-ref="mypCut"/>
- <aop:after-throwing method="doAfterThrowing" pointcut-ref="mypCut"/>
- <aop:after method="doAfter" pointcut-ref="mypCut"/>
- <aop:around method="doBasicProfiling" pointcut-ref="mypCut"/>
- </aop:aspect>
- </aop:config>
- </beans>
4)测试
- package com.tech.xml.test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.tech.aop.service.CustomerService;
- public class TestXmlAop {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
- CustomerService service = (CustomerService)ac.getBean("customerService");
- service.save("abc");
- }
- }
输出结果:
- 前置通知
- 进入方法
- 这是save方法
- 后置通知
- 最终通知
- 退出 方法
三、Spring AOP API
在Spring1.2中使用底层的Spring AOP API来实现AOP。当然,Spring3也是完全与其兼容的。我们可以借其窥探一下底层实现。在此不做介绍。
需要的jar包
总结
Spring AOP是基于代理的,是运行时绑定的。合理的运用AOP,将使软件的开发更加便捷,清晰。
Spring AOP的应用主要有以下几个方面:
- 性能监控,在方法调用前后记录调用时间,方法执行太长或超时报警。
- 工作流系统,工作流系统需要将业务代码和流程引擎代码混合在一起执行,那么我们可以使用AOP将其分离,并动态挂接业务。
- 权限验证,方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉。
- 缓存代理,缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
- 软件破解,使用AOP修改软件的验证类的判断逻辑。
- 记录日志,在方法执行前后记录系统日志。
相关推荐
Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...
Spring AOP,全称为Aspect Oriented Programming,是面向切面编程的一种编程范式,它是对传统的面向对象编程(OOP)的一种补充。在OOP中,核心是对象,而在AOP中,核心则是切面。切面是关注点的模块化,即程序中的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...
3、对spring aop认识模糊的,不清楚如何实现Java 自定义注解的 4、想看spring aop 注解实现记录系统日志并入库等 二、能学到什么 1、收获可用源码 2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑...
Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...
Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许开发者在不修改源代码的情况下,通过插入切面来增强或改变程序的行为。在本教程中,我们将深入探讨Spring AOP的不同使用方法,包括定义切点、通知类型...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要模块,它通过提供声明式的方式来实现面向切面编程,从而简化了应用程序的开发和维护。在Spring AOP中,我们无需深入到每个...
现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...
Spring AOP 和 Spring IOC 是 Spring 框架的两个核心组件,它们对于任何基于 Java 的企业级应用开发都至关重要。Spring AOP(面向切面编程)允许开发者在不修改源代码的情况下,通过“切面”来插入新的行为或增强已...
面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。...利用Java反射机制和Spring AOP框架,开发者可以方便地实现AOP,从而提升代码的模块化和可维护性。
**Spring AOP 实现机制详解** Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许程序员在不修改源代码的情况下,通过在运行时插入额外的行为(如日志记录、性能监控等)来增强对象的功能。动态代理则是Spring AOP实现的核心技术之一...
### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)逐渐暴露出难以应对某些横切关注点(cross-cutting concerns)的问题。为了解决这一挑战,面向方面编程...
在讨论Spring AOP(面向切面编程)时,首先需要理解几个核心概念。Spring AOP 是Spring框架提供的一个功能模块,它允许开发者将横切关注点(cross-cutting concerns)从业务逻辑中解耦出来,通过在方法调用前后进行...
### Spring AOP 实现流程日志跟踪 #### 一、背景与目的 在现代软件开发过程中,为了确保系统的稳定性和可维护性,通常会引入非功能性的需求来增强应用程序的功能,比如日志记录、安全控制等。这些需求往往不是业务...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理等。在Java应用中,AOP通过代理模式实现了切面编程,使得我们可以将业务逻辑...
### Spring AOP 入门详解 #### 一、Spring AOP 概述 Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个关键特性,它为开发者提供了在运行时动态添加代码(即横切关注点或切面)到已有...
Spring源码最难问题:当Spring AOP遇上循环依赖 Spring源码中最难的问题之一是循环依赖问题,当Spring AOP遇上循环依赖时,该如何解决? Spring通过三级缓存机制解决循环依赖的问题。 在Spring中,bean的实例化...
Spring AOP,即Spring的面向切面编程模块,是Spring框架的重要组成部分,它允许开发者在不修改源代码的情况下,对程序进行横切关注点的处理,如日志、事务管理等。实现这一功能,主要依赖于三个核心的jar包:aop...
在`springAop1`这个压缩包中,可能包含了一个简单的应用示例,展示了如何定义一个切面类,以及如何在该类中定义通知方法。例如,我们可能会看到一个名为`LoggingAspect`的类,其中包含了`@Before`注解的方法,用于在...