您的位置:首页 > 编程语言 > Java开发

Spring AOP 学习小结

2012-05-03 10:27 429 查看
一、AOP 概念

Joinpoint:它定义在哪里加入你的逻辑功能,对于Spring AOP,Jointpoint指的就是Method。

Advice:特定的Jointpoint处运行的代码,对于Spring AOP 来讲,有Before advice、AfterreturningAdvice、ThrowAdvice、AroundAdvice(MethodInteceptor)等。

Pointcut:一组Joinpoint,就是说一个Advice可能在多个地方织入,

Aspect:这个我一直迷惑,它实际是Advice和Pointcut的组合,但是Spring AOP 中的Advisor也是这样一个东西,但是Spring中为什么叫Advisor而不叫做Aspect。

Weaving:将Aspect加入到程序代码的过程,对于Spring AOP,由ProxyFactory或者ProxyFactoryBean负责织入动作。

Target:这个很容易理解,就是需要Aspect功能的对象。

Introduction:引入,就是向对象中加入新的属性或方法,一般是一个实例一个引用对象。当然如果不引入属性或者引入的属性做了线程安全性处理或者只读属性,则一个Class一个引用也是可以的(自己理解)。Per-class lifecycle or per-instance life cycle

二、AOP 种类

1、静态织入:指在编译时期就织入Aspect代码,AspectJ好像是这样做的。

2、动态织入:在运行时期织入,Spring AOP属于动态织入,动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行(性能较差)。

三、Spring AOP 代理原理

Spring AOP 是使用代理来完成的,Spring 会使用下面两种方式的其中一种来创建代理:

1、JDK动态代理,特点只能代理接口,性能相对较差,需要设定一组代理接口。

2、CGLIB 代理,可代理接口和类(final method除外),性能较高(生成字节码)。

四、Spring AOP 通知类型

1、BeforeAdvice:前置通知需实现MethodBeforeAdvice,但是该接口的Parent是BeforeAdvice,致于什么用处我想可能是扩展性需求的设计吧。或者Spring未来也并不局限于Method的JoinPoint(胡乱猜测)。BeforeAdvice可以修改目标的参数,也可以通过抛出异常来阻止目标运行。

2、AfterreturningAdvice:实现AfterreturningAdvice,我们无法修改方法的返回值,但是可以通过抛出异常阻止方法运行。

3、AroundAdvice:Spring 通过实现MethodInterceptor(aopalliance)来实现包围通知,最大特点是可以修改返回值,当然它在方法前后都加入了自己的逻辑代码,因此功能异常强大。通过MethodInvocation.proceed()来调用目标方法(甚至可以不调用)。

4、ThrowsAdvice:通过实现若干afterThrowing()来实现。

5、IntroductionInterceptor:Spring 的默认实现为DelegatingIntroductionInterceptor

五、Spring AOP Pointcut

以上只是Advice,如果不指定切入点,Spring 则使用所有可能的Jointpoint进行织入(当然如果你在Advice中进行方法检查除外)。因此切入点在AOP中扮演一个十分重要的角色。Spring 2.0 推荐使用AspectJ的Annocation的切入点表达式来定义切入点,或者使用<aop:xxx/>来定义AOP,这方面本篇不做考虑。

1、Pointcut:它是Spring AOP Pointcut的核心,定义了getClassFilter()和getMethodMatcher()两个方法。

2、ClassFilter:定义了matches(Class cls)一个方法。

3、MethodMatcher() 定义了matches(Method,Class),isRuntime(),matches(Mathod,Class,Object[])三个方法,如果isRuntime()返回true则表示为动态代理(实际是动态代理的动态代理),则调用第三个方法(每访问一次调用一次),否则调用第一个方法(并且只调用一次)

4、Spring AOP 静态切入点的几个实现。

ComposablePointcut 太复杂一个切入点无法表达就用这个,union MethodMatcher和ClassFilter或者intersection MethodMatcher、ClassFilter和Pointcut。为什么不实现union Pointcut? 而只能通过Pointcuts类对Pointcut进行union操作。

ControlFlowPointcut 想对程序的运行过程进行追踪就用这个

DynamicMatchMatcherPointcut 想用动态AOP 就用这个

JdkRegexpMethodPointcut 想使用正则表达式就用这个

Perl5RegexpMethodPointcut

NameMatchMethodPointcut
想用方法名字来匹配就用这个

StaticMethodMatcherPointcut 静态切入点就用这个

没有人反对你直接实现Pointcut:)。

六、Spring AOP 中的Advisor其实就是Aspect

1、 PointcutAdvisor

其实一般使用DefaultPointcutAdvisor就足够了,给它Advice和Pointcut。

当然如果想少写那么几行代码也可以使用NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。

更多Advisor可以查看API文档。

2、 IntroductionAdvisor

默认实现为DefaultIntroductionAdvisor。

七、AOP ProxyFactory

使用代码实现AOP 可使用ProxyFactory

声明式AOP 可使用ProxyFactoryBean

ProxyFactoryBean 需要设定 target,interceptorNames(可以是Advice或者Advisor,注意顺序)

对接口代理需设置proxyInterfaces

八、自动代理

BeanNameAutoProxyCreator


Java代码







<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"><value>jdk*,onlyJdk</value></property> <property name="interceptorNames"> <list> <value>myInterceptor</value> </list> </property> </bean>

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames"><value>jdk*,onlyJdk</value></property>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>


DefaultAdvisorAutoProxyCreator

Java代码







<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> <property name="transactionInterceptor" ref="transactionInterceptor"/> </bean> <bean id="customAdvisor" class="com.mycompany.MyAdvisor"/> <bean id="businessObject1" class="com.mycompany.BusinessObject1"> <!-- Properties omitted --> </bean> <bean id="businessObject2" class="com.mycompany.BusinessObject2"/>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
<bean id="businessObject1" class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>


九、Spring 2.0 AOP 略

以上为本人这段时间来看Spring AOP的一些学习体会,有什么说的不对的地方请批评指正。

分享到:




JDK 1.5 泛型事例一 |

Spring AOP 部分Class的UML图

2006-12-21 10:10
浏览 38817
评论(15)
论坛回复 / 浏览 (15 / 17994)
分类:企业架构
相关推荐

评论

15 楼
Hejrcc 2007-07-01
写得非常好!

关于 AOP 的几个基础概念,我感觉Spring 的参考文档上面讲得没有《Pro Spring》这本书上讲的好。

比较一下:

Spring Reference:

引用
Pointcut: A predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points
as matched by pointcut expressions is central to AOP: Spring uses the AspectJ pointcut language by default.

《Pro Spring》

引用
A pointcut is a collection of joinpoints that you use to define when advice should be executed. By creating pointcuts, you gain fine-grained control over how you apply advice to the components in your application. As mentioned previously,
a typical joinpoint is a method invocation. A typical pointcut is the collection of all method invocations in a particular class. Often you can compose pointcuts in complex relationships to further constrain when advice is executed. We discuss pointcut composition
in more detail in the next chapter.

我觉得《Pro Spring》这本书写得实在是太好了,非常容易懂。

而且,这本书的作者之一也是Spring 的主设计师:Rob Harrop. 

我一直以为,最好的书籍莫过于自带的文档。

当是当我看过《Pro Spring》这本书之后,感觉比看Spring的参考文档学习起来快多了,可谓事半功倍。。。

大家以为如何?

刚开始我想看文档来学Spring AOP,可是文档上面又没有完整例子,而且看起来也不是很容易懂,是不是学习方法的问题?

各位有什么好的建议?

14 楼
magice 2007-05-26

jamesby 写道
Aspect:这个我一直迷惑,它实际是Advice和Pointcut的组合,但是Spring AOP 中的Advisor也是这样一个东西,但是Spring中为什么叫Advisor而不叫做Aspect

Aspect是Advice(通知)在抽象概念上的表述,如果说用把Aspect用类来类比的话,那么Advice就是其Aspect具体的实现。但绝对与Advice+Pointcut的组合没有关系,这两者的组合在spring中有另外一个名词就是“Advisor”

jamesby 写道
三、Spring AOP 代理原理

Spring AOP 是使用代理来完成的,Spring 会使用下面两种方式的其中一种来创建代理:

1、JDK动态代理,特点只能代理接口,性能相对较差,需要设定一组代理接口。

2、CGLIB 代理,可代理接口和类(final method除外),性能较高(生成字节码)。

1。“JDK动态代理”与“CGLIB代理”的性能差别楼主恰好说反了,JDK动态代理是在1.x中是要比CGLIB快一些,但是目前2.0版本应该差不多了。

2。其实他们两者最主要区别还不在于性能上的差别,主要是要看实际的项目的特点(比如说该项目是否一个遗留系统)

a)JDK动态代理:使用接口于实现分离,面向接口编程是spring推荐的方式。

b)CGLIB代理: 主要适用于改造遗留系统,这些系统一般不会继承特定的接口。

以下是spring2.0文档对其进行的一些阐述:

引用

Imagine that in our example above, there was no Person interface: we needed to advise a class called Person that didn't implement any business interface. In this case, you can configure Spring to use CGLIB proxying, rather than dynamic proxies. Simply set the
proxyTargetClass property on the ProxyFactoryBean above to true.
While it's best to program to interfaces, rather than classes, the ability to advise classes that don't implement interfaces can be useful when working with legacy code. (In general, Spring isn't prescriptive. While it makes it easy to apply good practices,
it avoids forcing a particular approach.)

引用

There's little performance difference between CGLIB proxying and dynamic proxies. As of Spring 1.0,
dynamic proxies are slightly faster. However, this may change in the future. Performance should not be a decisive consideration in this case

13 楼
xrc8088 2007-04-11
To bencode:

是不是还要在applicationContext.xml中加上<aop:aspectj-autoproxy proxy-target-class="true"/> proxy-target-class="true"它表示代理的是类

12 楼
realreal2000 2007-04-05
学习中,又涨了些知识

11 楼
shaucle 2007-03-30
写得非常不错!

10 楼
xly_971223 2007-03-29

switchhub 写道
package com.longthsoft.learn.spring;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

@Aspect

public class SimpleAspect {

@Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())")

public void simplePointcut() { }

@AfterReturning(pointcut="simplePointcut()")

public void simpleAdvice() {

System.out.println("Merry Christmas");

}

}

这段代码不明白!!!

我是这样理解的 不知道对不对 请高手给指正

@Aspect 声明了这个类是一个切面。 切面=切入点+处理 下面分别定义了切入点和处理

@Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())") 这是定义了一个切入点

@AfterReturning(pointcut="simplePointcut()") 定义了一个AfterReturning类型的处理,处理的是simplePointcut()这个切入点中匹配的方法

9 楼
jamesby 2007-03-25
annotation的没有用过,不过这应该是一个AfterReturning 类型的AOP配置!

其实也就是搞懂 @Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())")

的意思就可以拉。

可参考Spring 2 Reference文档。

8 楼
switchhub 2007-03-25
package com.longthsoft.learn.spring;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

@Aspect

public class SimpleAspect {

@Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())")

public void simplePointcut() { }

@AfterReturning(pointcut="simplePointcut()")

public void simpleAdvice() {

System.out.println("Merry Christmas");

}

}

这段代码不明白!!!

7 楼
bencode 2007-02-03

引用
@Aspect

这种 和 在 xml中 声明

引用

<aop:config>

<aop:advisor id="userManagerTx" advice-ref="userManagerTxAdvice" pointcut="execution(* *..service.UserManager.*(..))" order="0"/>

<aop:advisor id="userManagerSecurity" advice-ref="userSecurityAdvice" pointcut="execution(* *..service.UserManager.saveUser(..))" order="1"/>

<aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Manager.*(..))" order="2"/>

</aop:config>

似乎都可以, 大家都习惯用哪种? 各有什么优缺点。

Java 1.5 支持元注释, 所以你可以任意选用XML还是元注释方式

但Java 1.5以前版本,只能用XML了

6 楼
lighter 2007-01-29
以前写过关于AOP的两篇文章

http://www.iteye.com/topic/41821

http://www.iteye.com/topic/42673

都是比较简单的实例和一些讲解

5 楼
JavaFlasher 2007-01-29
@Aspect

这种 和 在 xml中 声明

引用

<aop:config>

<aop:advisor id="userManagerTx" advice-ref="userManagerTxAdvice" pointcut="execution(* *..service.UserManager.*(..))" order="0"/>

<aop:advisor id="userManagerSecurity" advice-ref="userSecurityAdvice" pointcut="execution(* *..service.UserManager.saveUser(..))" order="1"/>

<aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Manager.*(..))" order="2"/>

</aop:config>

似乎都可以, 大家都习惯用哪种? 各有什么优缺点。

4 楼
lnj2050 2006-12-26
Thank your very much!

3 楼
bencode 2006-12-24
嘿,楼主给出了所有的概念,我想在这里给一个完整的例子,以帮助初学者更好地理解,

你们可以先不必理会上面的概念,等运行这个例子后,再慢慢地做照着理解。

我使用的是Spring 2.0 的APO, 它引入了一种更加简单并且更强大的方式来定义切面。

马上开始吧:

首先建一个普通Java项目:com.longthsoft.learn.spring

把 spring.jar, commons-logging.jar, cglib-nodep-...jar, aspectjweaver.jar, aspectjrt.jar 放到 Build Path 下.

以止 lib 除了 spring 外, 其他的都可以在 spring 下载包的 lib 中找到

下面编码开始:

让我们先写两个简单的类:

Java代码







package com.longthsoft.learn.spring.models; public class A { public void sayHello() { System.out.println("Hello, I'm a"); } }

package com.longthsoft.learn.spring.models;

public class A {
public void sayHello() {
System.out.println("Hello, I'm a");
}
}


Java代码







package com.longthsoft.learn.spring.models; public class B { public void sayHi() { System.out.println("Hi, I'm b"); } }
package com.longthsoft.learn.spring.models;

public class B {
public void sayHi() {
System.out.println("Hi, I'm b");
}
}


没什么实际的东西, 只是小A和小B在打招呼

接下来把他们交给Spring吧(有点残忍)。

Java代码







<?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-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<bean id="a" class="com.longthsoft.learn.spring.models.A" />
<bean id="b" class="com.longthsoft.learn.spring.models.B" />
</beans>

<?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-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<bean id="a" class="com.longthsoft.learn.spring.models.A" />
<bean id="b" class="com.longthsoft.learn.spring.models.B" />
</beans>


接下来写个Boot

Java代码







package com.longthsoft.learn.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.longthsoft.learn.spring.models.A; import com.longthsoft.learn.spring.models.B; public final class Boot { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); A a = (A) ctx.getBean("a"); a.sayHello(); B b = (B) ctx.getBean("b"); b.sayHi(); } }

package com.longthsoft.learn.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.longthsoft.learn.spring.models.A;
import com.longthsoft.learn.spring.models.B;

public final class Boot {

public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
A a = (A) ctx.getBean("a");
a.sayHello();

B b = (B) ctx.getBean("b");
b.sayHi();
}

}


嘿, 这里的运行结果不帖了, 大家脑子里闪过即可。

圣诞到了, 小A小B 介绍完自己之后,也应该说句 "Merry Christmas"

Spring 说, 既然你们交给我, 这等 routine 就不用再麻烦了, 直接一并处理掉。

于是:

Java代码







package com.longthsoft.learn.spring; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class SimpleAspect { @Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())") public void simplePointcut() { } @AfterReturning(pointcut="simplePointcut()") public void simpleAdvice() { System.out.println("Merry Christmas"); } }
package com.longthsoft.learn.spring;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SimpleAspect {

@Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())")
public void simplePointcut() { }

@AfterReturning(pointcut="simplePointcut()")
public void simpleAdvice() {
System.out.println("Merry Christmas");
}
}


然后修改一下配置文件

Java代码







<?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-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<aop:aspectj-autoproxy />

<bean id="a" class="com.longthsoft.learn.spring.models.A" />
<bean id="b" class="com.longthsoft.learn.spring.models.B" />

<bean id="simpleAspect" class="com.longthsoft.learn.spring.SimpleAspect" />
</beans>

<?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-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<aop:aspectj-autoproxy />

<bean id="a" class="com.longthsoft.learn.spring.models.A" />
<bean id="b" class="com.longthsoft.learn.spring.models.B" />

<bean id="simpleAspect" class="com.longthsoft.learn.spring.SimpleAspect" />
</beans>


OK, 运行一下:

Hello, I'm a

Merry Christmas

Hi, I'm b

Merry Christmas
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: