Spring AOP
Spring中所有的通知都是java类的形式编写,定义在什么地方应用通用的切入点通常编写在spring的配置文件中。需明确的几个概念:
通知(Advice):用于告知系统将有哪些新的行为。
切入点(Pointcut):定义了通知应该在应用到那些连接点。
目标对象(Target):被通知的对象。
代理(Proxy):将通知应用到目标对象后创建的对象。
代理Bean只有在第一次被应用系统需要的时候才被创建,如果使用的是ApplicationContext,代理对象在BeanFactory 载入所有Bean的时候创建。
Spring有2种代理创建方式:
1.如果目标对象实现了一个或多个接口暴露的方法,Spring将使用JDK的java.lang.reflect.Proxy类创建代理,这个类让Spring动态产生一个新的类,它实现了所有的接口,织入了通知,并且代理对目标对象的所有请求。
2.如果目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类,在创建子类的时候,Spring将通过织入,并且将对目标对象的调 用委托给这个子类,使用这种方式应注意两个要点:
(1)对接口创建代理优于对类创建代理,因为这样会产生更加松耦合的系统,对类生成代理是让遗留系统或者 无法实现接口的第三方类库同样的可以得到通知,这种方式是备用方案
(2)标记为final的方法不能被通知,Spring是为目标类产生子类,任何需要被 通知的方法都会被复写,将通知织入,final方法是不可能做到的。
通知有以下几种:
1.Around(周围同志)---org.aopllliance.intercept.MethodInterceptor拦截对目标对象方法调用
2.Before(前通知)---org.springframework.aop.BeforeAdvice在目标方法被调用前调用
3.After(返回后通知)---org.springframework.aop.AfterRetruningAdvice在方法被调用之后调用
4.Throws(抛出后通知)---org.springframework.aop.ThrowsAdvice在目标方法抛出异常时调用
5.Introduction(引入)--- org.springframework.aop.IntroductionInterceptor
示例:
Public class AudienceAdvice implements MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice
{
//前通知要求实现的方法
public void before(Method method,Object[] args,Object target) throws Throwable
{
}
//返回后通知要求实现的方法,Object returnValue表示被调用方法的返回值
public void afterReturning(Object returnValue,Method method,Object[] args,Object target) throws Throwable
{
}
//抛出后通知不需要实现任何方法,它只是一个标记接口,告诉spring相应的通知要求处理被抛出的异常,除最后一个参数外,其他参数都是可选的
public void afterThrowing(Method method,Object[] args,Object target,NullPointerException e) throws Throwable
{
//当发生NullPointerException 时,记录日志
LOGGER.error("NPE thrown from "+method.getName());
}
}
其中的Method method参数,表示要使用这个通知的方法,第二个参数Object[] args是方法被调用时要传递的参数。最后一个是方法调用的目标也就是被调用方法所在的对象。
周围通知相当于前通知、后通知、抛出后通知的结合。
Public class AudienceAdvice implements MethodInterceptor
{
Public Object invoke(MethodInvocation invocation) throws Throwable
{
Try
{
.............................. //在方法调用之前
Object returnValue=invocation.proceed(); 调用目标方法
............................. //在方法调用之后
}
catch(PerformanceException e)
{
............................. /在出现异常之后
}
}
}
切点
1.正则切点
切点的作用主要在于选择需要使用通知的方法,比如下面的正则表达式切点:
<bean id="performancePointcut" class="org.springframework.aop.support.JbkRegexpMethodPointcut">
<property name="pattern" value=".*perform" />
</bean>
// Pattern属性用于制定方法匹配所使用的切点模板,本例中被设置为一个正则表达式,它应该匹配任何类里名为perform的方法。
定义切点后,把切点与通知关联
<bean id="audienceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" value="audienceAdvice" />
<property name="pointcut" value="performancePointcut" />
</bean>
//DefaultPointcutAdvisor是一个通知者类,它只是把通知关联到一个切点。
也可以使用RegexpMethodPointcutAdvisor是一个特殊的通知者类,可以在一个Bean里面定义切点和通知者
<bean id="audienceAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" value="audienceAdvice" />
<property name="pattern" value=".*perform" />
</bean>
2.定义AspectJ切点
正则表达式虽然可以作为切点定义语言来使用,但是它并不是针对切点而创建的,其主要用途还是文本解析。AspectJ里定义切点的方法就可以看出AspectJ的切点语言是一种真正的切点表达式语言。
<bean id="performancePointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="expression" value="execution(* Performer+.perform(..))" />
</bean>
可以使用DefaultPointcutAdvisor把它和通知关联起来,就像前面一样。同样,也可以设置一个特殊的通知者
<bean id="audienceAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="advice" value="audienceAdvice" />
<property name="expression" value="execution(* *.perform(..))" />
</bean>
execution(* *.perform(..))
execution表示执行方法时,* *表示任意返回类型,.perform表示perform方法,(..)表示任意参数设置。
使用ProxyFactoryBean
<bean id="duke" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>genericdaotest.dao.PersonDao</value>
</property>
<property name="target">
<bean parent="abstractDaoTarget">
<constructor-arg>
<value>genericdaotest.domain.Person</value>
</constructor-arg>
</bean>
</property>
<property name="interceptorNames">
<list>
<value>audienceAdvisor</value>
</list>
</property>
</bean>
Spring里面的ProxyFactoryBean是个工厂Bean,用于生成一个代理,把一个或者多个拦截者(和通知者)应用到Bean,有target、interceptorNames、proxyInterfaces三个属性,后两个都是数组属性target表示要代理的对象。
interceptorNames属性告诉ProxyFactoryBean哪个通知者要应用于被代理的
beanproxyInterfaces告诉ProxyFactoryBean代理应该实现哪个接口。本例中代理的是genericdaotest.dao.PersonDao接口。
target告诉ProxyFactoryBean,哪个Bean是代理。
自动代理
使用ProxyFactoryBean来显式的创建AOP代理在很多场合下,会使编写配置文件的工作量大大增加;由于要从ProxyFactoryBean获得代理对象,也会使应用和Spring之间的耦合度增加。下面介绍使用Spring提供的自动代理机制来解决这类问题。
1.使用BeanNameAutoProxyCreator
Spring提供的BeanNameAutoProxyCreator类允许我们通过Bean的name属性来指定代理的Bean。它暴露了java.lang.String[]类型的beanNames和 interceptorNames属性。beanNames可以指定被代理的Bean名字列表,支持“*”通配符,例如“*DAO”表示所有名字以“DAO”结尾的Bean。interceptorNames指定通知(Advice)列表,或者通知者(Advisor)列表。
下面通过一个例程来演示如何使用BeanNameAutoProxyCreator。在例子中,有两个Bean:TestBeanA和BeanB,并在TestMain类中的main方法中调用其MyMethod()方法。自动代理将会在方法调用前自动的执行配置的前置通知,输出提示信息。
新建一个名字为AOP_Test4.10的工程,添加Spring的IoC和AOP库后,新建一aop.test包,再分别创建两个类TestBeanA和BeanB,添加MyMethod()方法,代码如下:
package aop.test;
public class TestBeanA
{
public void MyMethod()
{
System.out.println(this.getClass().getName() + ".MyMethod() is run!");
}
}
package aop.test;
public class BeanB
{
public void MyMethod()
{
System.out.println(this.getClass().getName() + ".MyMethod() is run!");
}
}
再创建前置通知类BeforeAdvice:
package aop.test;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeAdvice implements MethodBeforeAdvice
{
public void before(Method method, Object[] args, Object target) throws Throwable
{
System.out.println(method.getName() + "(),将要运行!");
}
}
最后创建含有main方法的测试类TestMain:
package aop.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain
{
public static void main(String[] args)
{
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
TestBeanA beanA = (TestBeanA)ac.getBean("TestBeanA");
beanA.MyMethod();
BeanB beanB = (BeanB)ac.getBean("BeanB");
beanB.MyMethod();
}
}
在配置文件中配置Bean和自动代理Bean,完成后代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans …………>
<bean id="TestBeanA" class="aop.test.TestBeanA"/>
<bean id="BeanB" class="aop.test.BeanB"/>
<bean id="BeforeAdvice" class="aop.test.BeforeAdvice"></bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>Test*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>BeforeAdvice</value>
</list>
</property>
</bean>
</beans>
运行主类,输出结果如下:
可以看到,在主类TestMain中,我们是直接从Spring IoC容器中获取收管Bean而不是像以前那样从ProxyFactoryBean中获取代理,但是我们的前置通知BeforeAdvice仍然在TestBeanA对象的MyMethod()方法执行前被触发,这说明我们的自动代理正在工作。
2.使用DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator允许我们只需定义相应的Advisor通知者,就可以完成自动代理。配置好DefaultAdvisorAutoProxyCreator受管Bean后,它会自动查找配置文件中定义的Advisor,并将它们作用于所有的Bean。
修改例程4.10的配置文件,使用DefaultAdvisorAutoProxyCreator来完成自动代理。完成后配置文件代码如下(本例完整工程代码见例程4.11):
<?xml version="1.0" encoding="UTF-8"?>
<beans ……>
<bean id="TestBeanA" class="aop.test.TestBeanA" />
<bean id="BeanB" class="aop.test.BeanB" />
<bean id="BeforeAdvice" class="aop.test.BeforeAdvice"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
<bean class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="BeforeAdvice" />
<property name="mappedNames">
<list>
<value>*Method*</value>
</list>
</property>
</bean>
</beans>
运行主类输出结果如下:
分享到:
相关推荐
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`注解的方法,用于在...