Spring的AOP

本文详细介绍了面向切面编程(AOP)的概念及其在Spring框架中的应用。覆盖了AOP的基本原理,包括切面、切入点和增强处理等内容,并通过示例展示了如何使用AspectJ和Spring AOP实现日志记录等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


关于AOP

AOP(Aspect Orient Programming),也就是面向切面编程,是作为面向对象编程的补充。

    面向对象编程是静态地将程序分解成各个层次的对象,面向切面编程是动态地将程序运行过程分解成各个切面。

在实际应用中,AOP常用于处理一些具有横切性质(各个模块中的交叉关注点)的系统级服务,如事务管理、安全检查、缓存、对象池管理等

AspectJ框架

AspectJ是一个基于Java语言的AOP框架,即Eclipse的一个开源子项目,提供了强大的AOP功能。

其主要包括两部分:第一部分定义了如何表达、定义AOP编程中的语法规范,很多其他语言都借鉴了AspectJ中的很多设计,如从spring2.0开始,spring AOP引入了对AspectJ的支持,并使自身的APIAspectJ保持一致;另外一部分是工具部分,包括编译器、调试工具等。

1.写测试类

 

     Public aspect LogAspect{
		//定义一个Pointcut,其名为logPointcut
		Pointcut logPoincut()
			:execution(void Hello.sayHello());
		//在logPointcut之后执行下面代码块
		After():logPointcut(){
			System.out.println(“记录日志…”);
		}
	}

 

  

    2.编译

         Ajc –d logAspect.java

         此处通过AspectJ的编译增强了Hello.class类的功能,因此AspectJ被称为编译时增强的AOP框架。

 

实质:

AOP框架特征:只处理程序执行中特定切入点(Pointcut),而不与具体某个具体类耦合。

AOP代理其实是由AOP框架动态生成一个对象,该对象即包含了目标对象的全部方法,也在特定切入点增强了处理(即增加了AOP方法);

结构示意图:


 

 

Spring AOP的支持

 

    Spring默认采用Java动态代理来创建AOP代理,也可以强制使用CGLIB代理;

    SpringAOP通常和Spring Ioc容器一起使用,并没有提供一种全面的AOP解决方案与AspectJ竞争,如:spring目前仅支持将方法调用作为连接点(Joinpoint),如果需要把对Field的访问和更新也作为增强处理的连接点,需要考虑用AspectJ框架。

 

组成部分:

       定义普通业务组件;

定义切入点,一个切入点可能横切多个业务组件;

定义增强处理,即在AOP框架为普通业务组件织入的动作处理。

 

AOP代理的方法:

    = 增强处理 + 被代理对象的方法

 

加入包:

       org.springframework.aop-3.1.1.RELEASE.jar

       aspectjrt.jar

aspectjweaver.jar

aopalliance.jar

cglib-2.1.3.jar(缺少会出现Cannot proxy target class because CGLIB2…异常)

 

基于annotation配置 

  1、spring.xml加入

 

<!-- 设置扫描组件 -->
<context:component-scan base-package="com.mvc.aop" annotation-config="true">
</context:component-scan>
<!-- 启动组件注解 -->
<context:annotation-config/>
<!-- 启动@AspectJ支持 -->
<aop:aspectj-autoproxy/>

 

  2、定义Bean的增强效果

 

package com.mvc.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

//定义一个切面,使用Aspect修饰后,spring 不会把该bean进行增强处理
@Aspect
public class BeforAdviceTest {
	//所有方法执行作为切入点
	@Before("excution(com.mvc.aop.*)")
	public void authority(){
		System.out.println("模拟执行权限检查...");
	}
}

 

   3、定义业务组件

 

package com.mvc.aop;

import org.springframework.stereotype.Component;



@Component
public class Chinese {

	public String sayHello(String name){
		return name + " hello,spring aop";
	}
}

 

  4、调用组件方法

   

New Chinese().sayHello(“test”);  //输出test hello,spring aop.

 

 

基于Xml配置文件的管理方式

<aop:aspectj-autoproxy/>Xml方式只能选取一种方法

 

  1、XML的配置文件
        <bean id="beforeAdviceBean" class="com.mvc.aop.BeforAdviceTest"></bean>
	<aop:config>
		<!-- 将BeforAdvicTest转换成切面Bean -->
		<aop:aspect id="beforeAdviceAspect" ref="beforeAdviceBean" order="1">
			<!-- 配置增强处理方法 -->
			<aop:before method="authority" pointcut="execution(* com.mvc.aop.*.*(..))"/>
		</aop:aspect>
	  </aop:config>
 

ProxyFactoryBean(一):只实现接口类型

  1、xml的配置

 

         <!-- 目标对象 -->
	 <bean id="chinese" class="com.mvc.aop.Chinese"></bean>
	 
	 <!-- Advice类 -->
	 <bean id="logAdvisor" class="com.mvc.aop.English"></bean>
	 
	 <bean id="human" class="org.springframework.aop.framework.ProxyFactoryBean">
	 	<!-- 指定目标对象 -->
	 	<property name="target">
			<ref local="chinese" />
		</property>
		<!-- 值为true时表示如果没有明确指定要代理的接口类型,会自动检测检测目标对象所实现的接口类型并进行代理 -->
		<property name="proxyTargetClass">
			<value>false</value>
		</property>
		<!-- 指定目标对象要实现的接口类型 -->
		<property name="proxyInterfaces">
			<list>
				<value>com.mvc.aop.Human</value>
			</list>
		</property>
		
		<!-- 可将多个Advice、拦截器、Advisor织入到目标对象 ,达到增强效果-->
		<property name="interceptorNames">  
                    <list>  
                      <value>logAdvisor</value>  
                   </list>  
                 </property>
        </bean>
 

 

  2、Advice类

 

public class English implements MethodBeforeAdvice{
	@Override
	public void before(Method arg0, Object[] arg1, Object arg2)
			throws Throwable {
		System.out.println("hello, I am English!");
	}
}
 

ProxyFactoryBean(二):加入RegexpMethodPointcutAdvisor

  xml配置
         <!-- 目标对象 -->
	 <bean id="chinese" class="com.mvc.aop.Chinese"></bean>
	 
	 <!-- advice类 -->
	 <bean id="log" class="com.mvc.aop.English"></bean>
	 
	 <bean id="human" class="org.springframework.aop.framework.ProxyFactoryBean">
	 	<!-- 指定目标对象 -->
	 	<property name="target">
			<ref local="chinese" />
		</property>
		<!-- 值为true时表示如果没有明确指定要代理的接口类型,会自动检测检测目标对象所实现的接口类型并进行代理 -->
		<property name="proxyTargetClass">
			<value>false</value>
		</property>
		<!-- 指定目标对象要实现的接口类型 -->
		<property name="proxyInterfaces">
			<list>
				<value>com.mvc.aop.Human</value>
			</list>
		</property>
		
		<!-- 可将多个Advice、拦截器、Advisor织入到目标对象 ,达到增强效果-->
		<property name="interceptorNames">  
            <list>  
                <value>logAdvisor</value>  
            </list>  
        </property>
	 </bean>
	<!--代理目标类的指定方法-->  
	<bean id="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		  
        <property name="advice">  
            <ref bean="log"/>  
        </property>  
     		 <!--指定要代理的方法-->  
    	<property name="patterns">  
            <value>.*say.*</value>  
        </property>  
   	</bean>

 
MethodInterceptor配置方式:
自定义注解的代码:
package com.qunar.wireless.ugc.controllor.web;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired  {
  
}
 
自定义的方法拦截器:
import javax.servlet.http.HttpServletRequest;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.qunar.wireless.ugc.controllor.web.LoginRequired;

/**
 * @author tao.zhang
 * @create-time 2012-2-31
 */
public class LoginRequiredInterceptor1 implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
            
        Object[] ars = mi.getArguments();
                 
       
        for(Object o :ars){
            if(o instanceof HttpServletRequest){
               System.out.println("------------this is a HttpServletRequest Parameter------------ ");
            }
        }
        // 判断该方法是否加了@LoginRequired 注解
        if(mi.getMethod().isAnnotationPresent(LoginRequired.class)){
             System.out.println("----------this method is added @LoginRequired-------------------------");
        }

       //执行被拦截的方法,切记,如果此方法不调用,则被拦截的方法不会被执行。
        return mi.proceed();
    }


   

}
 
配置文件:
<bean id="springMethodInterceptor" class="com.qunar.wireless.ugc.interceptor.LoginRequiredInterceptor1" ></bean>
<aop:config>
    <!--切入点-->
    <aop:pointcut id="loginPoint" expression="execution(public * com.qunar.wireless.ugc.controllor.web.*.*(..)) "/> 
    <!--在该切入点使用自定义拦截器-->
    <aop:advisor pointcut-ref="loginPoint" advice-ref="springMethodInterceptor"/>             
</aop:config>
 
###Spring AOP 的概念 AOP(Aspect-Oriented Programming)即面向切面编程,是一种编程范式,旨在通过分离横切关注点来提高模块化程度。在 Spring 框架中,AOP 被广泛用于实现诸如日志记录、事务管理、安全性等通用功能,这些功能通常与业务逻辑无关但又需要在多个地方重复使用。 Spring AOP 主要是基于 AspectJ 实现的,尽管 AspectJ 是一个独立的 AOP 框架,并不是 Spring 的组成部分,但它通常与 Spring 一起使用以提供更强大的 AOP 功能[^1]。Spring AOP 支持两种方式来定义切面:基于 XML 配置文件的方式基于注解的方式。 ###Spring AOP原理 Spring AOP 使用运行时代理来实现 AOP 功能,这意味着它会在运行时动态生成代理对象。对于实现了接口的类,Spring AOP 默认使用 JDK 动态代理;而对于没有实现接口的类,则会使用 CGLIB 代理[^4]。这种方式允许在不修改原始代码的情况下向程序中添加新的行为。 织入(Weaving)是将增强(advice)应用到目标对象的过程,Spring AOP 在运行时进行织入操作[^3]。当创建了代理对象后,所有对目标对象方法的调用都会被拦截,并且可以插入额外的操作,比如在方法执行前后做一些处理。 ###Spring AOP 的使用教程 要开始使用 Spring AOP,首先需要确保项目中包含了必要的依赖。如果使用 Maven 构建工具,可以在 `pom.xml` 文件中加入如下依赖: ```xml <!-- 引入aop依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 一旦添加了依赖并刷新了 Maven 项目,就可以开始编写切面了。下面是一个简单的例子,展示如何使用注解来定义一个切面: ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Method " + joinPoint.getSignature().getName() + " is called."); } } ``` 在这个示例中,`LoggingAspect` 类被标记为 `@Aspect` `@Component` 注解,这样 Spring 就能识别这是一个切面组件。`@Before` 注解指定了在哪些方法上应用前置通知(before advice),这里的表达式表示匹配 `com.example.service` 包下所有的方法。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值