- 浏览: 134647 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
zfcejb:
你好,这X-gen有源码参考吗
X-gen PPT下载——《研磨设计模式》 实战 -
1927105:
LZ研究过Hibernate4里的监听时间吗?我这边用4.3. ...
Hibernate4实战 之第六部分:基本实现原理 -
hbbbs:
看介绍 挺美的!
X-gen PPT下载——《研磨设计模式》 实战 -
jenmhdn:
即这个是综合运用设计模式的
X-gen PPT下载——《研磨设计模式》 实战 -
jenmhdn:
很值得一看
X-gen PPT下载——《研磨设计模式》 实战
启用@AspectJ支持
通过在你的Spring的配置中引入下列元素来启用Spring对@AspectJ的支持:
<aop:aspectj-autoproxy/>
声明一个方面
在application context中定义的任意带有一个@Aspect切面(拥有@Aspect注解)的bean都将被Spring自动识别并用于配置在Spring AOP。
配置如:
声明一个切入点(pointcut)
使用 @Pointcut 注解来表示 ,示例如下:
切入点指定者的支持
Spring AOP 支持在切入点表达式中使用如下的AspectJ切入点指定者:
1:execution:匹配方法执行的连接点,这是你将会用到的Spring的最主要的切入点指定者。
2:within:限定匹配特定类型的连接点(在使用Spring AOP的时候,在匹配的类型中定义的方法的执行)。
3:this:限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中bean reference(Spring AOP 代理)是指定类型的实例。
4: target:限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中目标对象(被代理的appolication object)是指定类型的实例。
5: args:限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中参数是指定类型的实例。
6: @target:限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中执行的对象的类已经有指定类型的注解。
7: @args:限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中实际传入参数的运行时类型有指定类型的注解。
8: @within:限定匹配特定的连接点,其中连接点所在类型已指定注解(在使用Spring AOP的时候,所执行的方法所在类型已指定注解)。
9: @annotation:限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中连接点的主题有某种给定的注解
合并切入点表达式
切入点表达式可以使用‘&&', '||' 和 '!'来合并.还可以通过名字来指向切入点表达式。
切入点表达式的基本语法
Spring AOP 用户可能会经常使用 execution pointcut designator。执行表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。
类型匹配模式
1:*:匹配任何数量字符;比如模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型
2:..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数,可以使零到多个。
3: +:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
类型匹配模式示例
1:java.lang.String 匹配String类型;
2:java.*.String 匹配java包下的任何“一级子包”下的String类型;
如匹配java.lang.String,但不匹配java.lang.ss.String
3:java..* 匹配java包及任何子包下的任何类型;
如匹配java.lang.String、java.lang.annotation.Annotation
4:java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
5:java.lang.Number+ 匹配java.lang包下的任何Number的子类型;
如匹配java.lang.Integer,也匹配java.math.BigInteger
切入点表达式的基本示例,使用execution
1:public * *(..)
任何公共方法的执行
2:* cn.javass..IPointcutService.*()
cn.javass包及所有子包下IPointcutService接口中的任何无参方法
3:* cn.javass..*.*(..)
cn.javass包及所有子包下任何类的任何方法
4:* cn.javass..IPointcutService.*(*)
cn.javass包及所有子包下IPointcutService接口的任何只有一个参数方法
5:* (!cn.javass..IPointcutService+).*(..)
非“cn.javass包及所有子包下IPointcutService接口及子类型”的任何方法
6:* cn.javass..IPointcutService+.*()
cn.javass包及所有子包下IPointcutService接口及子类型的的任何无参方法
7:* cn.javass..IPointcut*.test*(java.util.Date)
cn.javass包及所有子包下IPointcut前缀类型的的以test开头的只有一个参数类型为java.util.Date的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的如定义方法:public void test(Object obj);即使执行时传入java.util.Date,也不会匹配的。
8:* cn.javass..IPointcut*.test*(..) throws IllegalArgumentException, ArrayIndexOutOfBoundsException
cn.javass包及所有子包下IPointcut前缀类型的的任何方法,且抛出IllegalArgumentException和ArrayIndexOutOfBoundsException异常
9:* (cn.javass..IPointcutService+ && java.io.Serializable+).*(..)
任何实现了cn.javass包及所有子包下IPointcutService接口和java.io.Serializable接口的类型的任何方法
10:@java.lang.Deprecated * *(..)
任何持有@java.lang.Deprecated注解的方法
11:@java.lang.Deprecated @cn.javass..Secure * *(..)
任何持有@java.lang.Deprecated和@cn.javass..Secure注解的方法
12:@(java.lang.Deprecated || cn.javass..Secure) * *(..)
任何持有@java.lang.Deprecated或@ cn.javass..Secure注解的方法
13:(@cn.javass..Secure *) *(..)
任何返回值类型持有@cn.javass..Secure的方法
14:* (@cn.javass..Secure *).*(..)
任何定义方法的类型持有@cn.javass..Secure的方法
15:* *(@cn.javass..Secure (*) , @cn.javass..Secure (*))
任何签名带有两个参数的方法,且这个两个参数都被@ Secure标记了,如public void test(@Secure String str1, @Secure String str1);
16:* *((@ cn.javass..Secure *))或* *(@ cn.javass..Secure *)
任何带有一个参数的方法,且该参数类型持有@ cn.javass..Secure;如public void test(Model model);且Model类上持有@Secure注解
17:* *(@cn.javass..Secure (@cn.javass..Secure *) ,@ cn.javass..Secure (@cn.javass..Secure *))
任何带有两个参数的方法,且这两个参数都被@ cn.javass..Secure标记了;且这两个参数的类型上都持有@ cn.javass..Secure;
18:* *(java.util.Map<cn.javass..Model, cn.javass..Model>, ..)
任何带有一个java.util.Map参数的方法,且该参数类型是以<cn.javass..Model, cn.javass..Model>为泛型参数;注意只匹配第一个参数为java.util.Map,不包括子类型;如public void test(HashMap<Model, Model> map, String str);将不匹配,必须使用“* *(java.util.HashMap<cn.javass..Model,cn.javass..Model>, ..)”进行匹配;而public void test(Map map, int i);也将不匹配,因为泛型参数不匹配
19:* *(java.util.Collection<@cn.javass..Secure *>)
任何带有一个参数(类型为java.util.Collection)的方法,且该参数类型是有一个泛型参数,该泛型参数类型上持有@cn.javass..Secure注解;如public void test(Collection<Model> collection);Model类型上持有@cn.javass..Secure
切入点表达式的基本示例,使用within匹配指定类型内的方法
1:within(cn.javass..*)
cn.javass包及子包下的任何方法执行
2:within(cn.javass..IPointcutService+)
cn.javass包或所有子包下IPointcutService类型及子类型的任何方法
3:within(@cn.javass..Secure *)
持有cn.javass..Secure注解的任何类型的任何方法必须是在目标对象上声明这个注解,在接口上声明的对它不起作用
切入点表达式的基本示例,使用this
使用“this(类型全限定名)”匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口方法也可以匹配;注意this中使用的表达式必须是类型全限定名,不支持通配符
1:this(cn.javass.spring.chapter6.service.IPointcutService)
当前AOP对象实现了 IPointcutService接口的任何方法
2:this(cn.javass.spring.chapter6.service.IIntroductionService)
当前AOP对象实现了 IIntroductionService接口的任何方法也可能是引入接口
切入点表达式的基本示例,使用target
使用“target(类型全限定名)”匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;注意target中使用的表达式必须是类型全限定名,不支持通配符
1:target(cn.javass.spring.chapter6.service.IPointcutService)
当前目标对象(非AOP对象)实现了 IPointcutService接口的任何方法
2:target(cn.javass.spring.chapter6.service.IIntroductionService)
当前目标对象(非AOP对象) 实现了IIntroductionService 接口的任何方法不可能是引入接口
切入点表达式的基本示例,使用args
使用“args(参数类型列表)”匹配当前执行的方法传入的参数为指定类型的执行方法;注意是匹配传入的参数类型,不是匹配方法签名的参数类型;参数类型列表中的参数必须是类型全限定名,通配符不支持;args属于动态切入点,这种切入点开销非常大,非特殊情况最好不要使用
1:args (java.io.Serializable,..)
任何一个以接受“传入参数类型为 java.io.Serializable” 开头,且其后可跟任意个任意类型的参数的方法执行,args指定的参数类型是在运行时动态匹配的
切入点表达式的基本示例,使用@within
使用“@within(注解类型)”匹配所以持有指定注解类型内的方法;注解类型也必须是全限定类型名
1:@within cn.javass.spring.chapter6.Secure)
任何目标对象对应的类型持有Secure注解的类方法;必须是在目标对象上声明这个注解,在接口上声明的对它不起作用
切入点表达式的基本示例,使用@target
使用“@target(注解类型)”匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;注解类型也必须是全限定类型名
1:@target (cn.javass.spring.chapter6.Secure)
任何目标对象持有Secure注解的类方法;必须是在目标对象上声明这个注解,在接口上声明的对它不起作用
切入点表达式的基本示例,使用@args
使用“@args(注解列表)”匹配当前执行的方法传入的参数持有指定注解的执行;注解类型也必须是全限定类型名
1:@args (cn.javass.spring.chapter6.Secure)
任何一个只接受一个参数的方法,且方法运行时传入的参数持有注解 cn.javass.spring.chapter6.Secure;动态切入点,类似于arg指示符;
切入点表达式的基本示例,使用@annotation
使用“@annotation(注解类型)”匹配当前执行方法持有指定注解的方法;注解类型也必须是全限定类型名
1:@annotation(cn.javass.spring.chapter6.Secure )
当前执行方法上持有注解 cn.javass.spring.chapter6.Secure将被匹配
切入点表达式的基本示例,使用bean
使用“bean(Bean id或名字通配符)”匹配特定名称的Bean对象的执行方法;Spring AOP扩展的,在AspectJ中无相应概念
1:bean(*Service)
匹配所有以Service命名(id或name)结尾的Bean
切入点表达式的基本示例,使用reference pointcut
引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持,如下所示:
java代码:
- @Pointcut(value="bean(*Service)") //命名切入点1
- private void pointcut1(){}
- @Pointcut(value="@args(cn.javass.spring.chapter6.Secure)") //命名切入点2
- private void pointcut2(){}
- @Before(value = "pointcut1() && pointcut2()") //引用命名切入点
- public void referencePointcutTest1(JoinPoint jp) {
- dump("pointcut1() && pointcut2()", jp);
- }
声明通知
通知是跟一个切入点表达式关联起来的,并且在切入点匹配的方法执行之前或者之后或者之前和之后运行。 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明过的切入点表达式。
前置通知(Before advice) ,使用 @Before 注解声明
返回后通知(After returning advice) ,使用 @AfterReturning注解声明
后通知(After (finally) advice) ,使用 @After注解声明
抛出后通知(After throwing advice) ,使用 @AfterThrowing注解声明
可以将抛出的异常绑定到通知的一个参数上 ,如下:
环绕通知(Around Advice) ,使用 @Around注解声明
给Advice传递参数
通常情况下,Advice都需要获取一定的参数,比如:Before需要截获传入的参数,而After需要获取方法的返回值等等。下面介绍两种方式
方式一:使用JoinPoint来给Advice的方法传递参数
Spring AOP提供使用org.aspectj.lang.JoinPoint类型获取连接点数据,任何通知方法的第一个参数都可以是JoinPoint(环绕通知是ProceedingJoinPoint,JoinPoint子类),当然第一个参数位置也可以是JoinPoint.StaticPart类型,这个只返回连接点的静态部分。
1:JoinPoint:提供访问当前被通知方法的目标对象、代理对象、方法参数等数据
java代码:
- public interface JoinPoint {
- String toString(); //连接点所在位置的相关信息
- String toShortString(); //连接点所在位置的简短相关信息
- String toLongString(); //连接点所在位置的全部相关信息
- Object getThis(); //返回AOP代理对象
- Object getTarget(); //返回目标对象
- Object[] getArgs(); //返回被通知方法参数列表
- Signature getSignature(); //返回当前连接点签名
- SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
- String getKind(); //连接点类型
- StaticPart getStaticPart(); //返回连接点静态部分
- }
2:ProceedingJoinPoint:用于环绕通知,使用proceed()方法来执行目标方法
3:JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等
4:示例:使用如下方式在通知方法上声明,必须是在第一个参数,然后使用jp.getArgs()就能获取到被通知方法参数:
方式二:使用args来给Advice的方法传递参数,示例如:
切入点表达式execution(* test(*)) && args(param) :
(1)首先execution(* test(*))匹配任何方法名为test,且有一个任何类型的参数;
(2)args(param)将首先查找通知方法上同名的参数,并在方法执行时(运行时)匹配传入的参数是使用该同名参数类型,即java.lang.String;如果匹配将把该被通知参数传递给通知方法上同名参数。
参数匹配的策略
1:可以通过“argNames”属性指定参数名 ,示例如:
2:如果第一个参数类型是JoinPoint、ProceedingJoinPoint或JoinPoint.StaticPart类型,应该从“argNames”属性省略掉该参数名(可选,写上也对),这些类型对象会自动传入的,但必须作为第一个参数 。示例如:
3:如果“ class文件中含有变量调试信息”,Spring将可以使用这些方法签名中的参数名来确定参数名,示例如下:
4:如果没有“ class文件中含有变量调试信息”,将尝试自己的参数匹配算法,如果发现参数绑定有二义性将抛出AmbiguousBindingException异常;对于只有一个绑定变量的切入点表达式,而通知方法只接受一个参数,说明绑定参数是明确的,从而能配对成功 ,示例如下:
@Before(value=" args(param)")
public void before1(JoinPoint jp, String param) {
System.out.println("===param:" + param);
}
5:以上策略失败将抛出IllegalArgumentException。
处理参数
java代码:
- @Around("execution(List<Account> find*(..)) &&" +
- "com.xyz.SystemArchitecture.inDataAccessLayer() && " + "args(accountHolderNamePattern)")
- public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern)
- throws Throwable {
- String newPattern = preProcess(accountHolderNamePattern);
- return pjp.proceed(new Object[] {newPattern});
- }
获取方法运行后的返回值
Advice执行的顺序
如果有多个通知想要在同一连接点运行会发生什么?Spring AOP 的执行通知的顺序跟AspectJ的一样。 在“进入”连接点的情况下,最高优先级的通知会先执行(所以上面给出的两个前置通知(before advice)中,优先级高的那个会先执行)。 在“退出”连接点的情况下,最高优先级的通知会最后执行。只需要记住通知是按照定义的顺序来执行的就可以了。
当定义在 不同的 切面里的两个通知都需要在一个相同的连接点中运行,那么除非你指定,否则执行的顺序是未知的。 你可以通过指定优先级来控制执行顺序。在Spring中可以在切面类中实现 org.springframework.core.Ordered 接口做到这一点。 在两个切面中,Ordered.getValue() 方法返回值较低的那个有更高的优先级。
java代码:
- 声明一个切面 :<aop:aspect>
- <aop:config>
- <aop:aspect id="myAspect" ref="adviceBean">
- ...
- </aop:aspect>
- </aop:config>
- <bean id="adviceBean" class="...">
- ...
- </bean>
- 声明一个切入点 :<aop:pointcut>
- <aop:config>
- <aop:pointcut id="businessService"
- expression="execution(* com.xyz.myapp.service.*.*(..))"/>
- </aop:config>
在切面里面声明一个切入点和声明一个顶级的切入点非常类似:
当需要连接子表达式的时候,'&'在XML中用起来非常不方便,所以关键字'and', 'or' 和 'not'可以分别用来代替'&', '||' 和 '!'。
java代码:
- 声明通知Advice,Before Advice
- <aop:aspect id="beforeExample" ref="aBean">
- <aop:before
- pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
- method="doAccessCheck"/>
- ...
- </aop:aspect>
- 返回后通知(After returning advice)
- <aop:aspect id="afterReturningExample" ref="aBean">
- <aop:after-returning
- pointcut-ref="dataAccessOperation"
- method="doAccessCheck"/>
- ...
- </aop:aspect>
java代码:
- 抛出异常后通知(After throwing advice)
- <aop:aspect id="afterThrowingExample" ref="aBean">
- <aop:after-throwing
- pointcut-ref="dataAccessOperation"
- thowing="dataAccessEx"
- method="doRecoveryActions"/>
- ...
- </aop:aspect>
- 后通知(After (finally) advice)
- <aop:aspect id="afterFinallyExample" ref="aBean">
- <aop:after
- pointcut-ref="dataAccessOperation"
- method="doReleaseLock"/>
- ...
- </aop:aspect>
Around通知
通知的参数,可以通过 arg-names 属性来实现
“advisors”这个概念来自Spring1.2对AOP的支持,在AspectJ中是没有等价的概念。 advisor就像一个小的自包含的切面,这个切面只有一个通知。
Spring AOP还是完全用AspectJ?
优先选用Spring的AOP,因为它不是一个人在战斗,Spring除了AOP,还有IOC,还有事务等其他功能。
如果你需要通知domain对象或其它没有在Spring容器中 管理的任意对象,那么你需要使用AspectJ。
Spring AOP中使用@AspectJ还是XML?
优先使用@AspectJ。
XML风格有两个缺点。第一是它不能完全将需求实现的地方封装到一个位置。DRY原则中说系统中的每一项知识都必须具有单一、无歧义、权威的表示。 当使用XML风格时,如何实现一个需求的知识被分割到支撑类的声明中以及XML配置文件中。当使用@AspectJ风格时就只有一个单独的模块 -切面- 信息被封装了起来。 第二是XML风格同@AspectJ风格所能表达的内容相比有更多的限制:仅仅支持"singleton"切面实例模型,并且不能在XML中组合命名连接点的声明。
Spring AOP使用JDK动态代理或者CGLIB来为目标对象创建代理。如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。
如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下问题:
1:无法通知(advise)Final 方法,因为他们不能被覆写。
2:将CGLIB 2二进制发行包放在classpath下面,JDK本身就提供了动态代理
3:强制使用CGLIB代理需要将 <aop:config> 的 proxy-target-class 属性设为true:
<aop:config proxy-target-class="true"></aop:config>
4:当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 <aop:aspectj-autoproxy> 的 proxy-target-class 属性:
<aop:aspectj-autoproxy proxy-target-class="true"/>
切入点的API
org.springframework.aop.Pointcut 是最核心的接口,用来将 通知应用于特定的类和方法,完整的接口定义如下:
1:将Pointcut接口分割成有利于重用类和方法匹配的两部分,以及进行更细粒度的操作组合(例如与另一个方法匹配实现进行“或操作”)。
2:ClassFilter接口用来将切入点限定在一个给定的类集合中。如果matches()方法总是返回true,所有目标类都将被匹配:
public interface ClassFilter {
boolean matches(Class clazz);
}
3:MethodMatcher接口通常更重要,完整的接口定义如下:
matches(Method, Class)方法用来测试这个切入点是否匹配目标类的指定方法。这将在AOP代理被创建的时候执行,这样可以避免在每次方法调用的时候都执行。如果matches(Method, Class )对于一个给定的方法返回true,并且isRuntime() 也返回true,那么matches(Method, Class , Object[])将在每个方法调用的时候被调用。这使得切入点在通知将被执行前可以查看传入到方法的参数。
大多数MethodMatcher是静态的,这意味着isRuntime()方法返回 false。在这种情况下,matches(Method, Class , Object[])永远不会被调用。
静态切入点
静态切入点基于方法和目标类进行切入点判断而不考虑方法的参数。在多数情况下,静态切入点是高效的、最好的选择。 Spring只在第一次调用方法时执行静态切入点:以后每次调用这个方法时就不需要再执行。
1:正则表达式切入点
正则表达式是最常用的描述静态切入点的方式,多数AOP框架都支持这种方式。org.springframework.aop.support.Perl5RegexpMethodPointcut是一个最基本的正则表达式切入点, 它使用Perl 5正则表达式语法。示例如下:
拦截around通知
Spring里使用方法拦截的around通知兼容AOP联盟接口。实现around通知的MethodInterceptor应当实现下面的接口:
提示:在invok方法里面不要忘记调用:invocation.proceed();
前置通知
后置通知
异常通知
如果连接点抛出异常,异常通知(throws advice)将在连接点返回后被调用。 Spring提供类型检查的异常通知,这意味着org.springframework.aop.ThrowsAdvice接口不包含任何方法:它只是一个标记接口用来标识 所给对象实现了一个或者多个针对特定类型的异常通知方法。这些方法应当满足下面的格式
afterThrowing([Method], [args], [target], subclassOfThrowable)
只有最后一个参数是必须的。因此异常通知方法对方法及参数的需求,方法的签名将从一到四个参数之间变化。 下面是一些throws通知的例子。
当一个RemoteException(包括它的子类)被抛出时,下面的通知会被调用:
引入通知
使用ProxyFactoryBean创建AOP代理
使用ProxyFactoryBean或者其它IoC相关类带来的最重要的好处之一就是创建AOP代理,这意味着通知和切入点也可以由IoC来管理。这是一个强大的功能并使得某些特定的解决方案成为可能
下面描述ProxyFactoryBean的属性:
1:proxyTargetClass:这个属性为true时,目标类本身被代理而不是目标类的接口。如果这个属性值被设为true,CGLIB代理将被创建
2:optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略。除非完全了解AOP代理如何处理优化,否则不推荐用户使用这个设置。目前这个属性仅用于CGLIB代理;对于JDK动态代理(缺省代理)无效。
3:frozen:用来控制代理工厂被配置之后,是否还允许修改通知。缺省值为false(即在代理被配置之后,不允许修改代理的配置)。
4:exposeProxy:决定当前代理是否被保存在一个ThreadLocal中以便被目标对象访问。(目标对象本身可以通过MethodInvocation来访问,因此不需要ThreadLocal。) 如果个目标对象需要获取代理而且exposeProxy属性被设为true,目标对象可以使用AopContext.currentProxy()方法。
5:aopProxyFactory:使用AopProxyFactory的实现。这提供了一种方法来自定义是否使用动态代理,CGLIB或其它代理策略。 缺省实现将根据情况选择动态代理或者CGLIB。一般情况下应该没有使用这个属性的需要;它是被设计来在Spring 1.1中添加新的代理类型的。
6:proxyInterfaces:需要代理的接口名的字符串数组。如果没有提供,将为目标类使用一个CGLIB代理
7:interceptorNames:Advisor的字符串数组,可以包括拦截器或其它通知的名字。顺序是很重要的,排在前面的将被优先服务。就是说列表里的第一个拦截器将能够第一个拦截调用。
这里的名字是当前工厂中bean的名字,包括父工厂中bean的名字。这里你不能使用bean的引用因为这会导致ProxyFactoryBean忽略通知的单例设置。
你可以把一个拦截器的名字加上一个星号作为后缀(*)。这将导致这个应用程序里所有名字以星号之前部分开头的advisor都被应用。
让我们看一个关于ProxyFactoryBean的简单例子,这个是对接口进行代理
java代码:
- <bean id="personTarget" class="com.mycompany.PersonImpl"></bean>
- <bean id="myAdvisor" class="com.mycompany.MyAdvisor"></bean>
- <bean id="debugInterceptor" class="org. DebugInterceptor"></bean>
- <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="proxyInterfaces"><value>com.Person</value></property>
- <property name="target"><ref local="personTarget"/></property>
- <property name="interceptorNames">
- <list>
- <value>myAdvisor</value>
- <value>debugInterceptor</value>
- </list>
- </property>
- </bean>
如果要对类进行代理,只需要把proxyTargetClass属性设为true
定义如下的接口:
写实现类如下:
写一个Before的Advice实现
定义如下的接口:
写实现类如下:
写一个Before的Advice实现
定义如下的接口:
写实现类如下:
写一个Before的Advice实现
配置文件如下:
java代码:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="myTarget" class="cn.javass.Spring3.aop1.Impl"/>
- <bean id="myBefore" class="cn.javass.Spring3.aop1.MyBefore"/>
- <bean id="myIn" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="proxyInterfaces">
- <value>cn.javass.Spring3.aop1.Api</value>
- </property>
- <property name="target"><ref local="myTarget"/></property>
- <property name="interceptorNames">
- <list>
- <value>beforeAdvisor</value>
- </list>
- </property>
- </bean>
- <bean id="beforeAdvisor"
- class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="advice">
- <ref local="myBefore"/>
- </property>
- <property name="patterns">
- <list>
- <value>.*</value>
- </list>
- </property>
- </bean>
- </beans>
客户端文件如下:
AOP与设计模式
AOP实际是设计模式的一种扩展,设计模式所追求的是降低代码之间的耦合度,增加程序的灵活性和可重用性,AOP实际上就是设计模式所追求的目标的一种实现。
所谓的分离关注就是将某一通用的需求功能从不相关的类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类 ,只要修改这个行为就可以,从而达到更好的可扩展性和复用性。
AOP包括三个清晰的开发步骤:
1: 功能横切:分解需求提取出横切关注点。
2: 实现分离:各自独立的实现这些关注点所需要完成的功能。
3: 功能回贴:在这一步里,方面集成器通过创建一个模块单元——方面来指定重组的规则。重组过程——也叫织入或结合——则使用这些信息来构建最终系统。
AOP与OOP开发的不同关键在于它处理横切关注点的方式,在AOP中,每个关注点的实现都不知道其它关注点是否会‘关注’它,如信用卡处理模块并不知道其它的关注点实现正在为它做日志和验证操作。
应该拦截字段吗?
我们在实现AOP的时候,想要修改某个属性。者通常不是一种好的做法,因为属性通常应该在类的内部进行访问,他体现了类的封装性,如果拦截字段并修改它,那么就会破坏这种封装性。
而拦截方法不会破坏封装性,因为这些方法本身就是能够被外界访问的。 如果确实需要拦截字段,通常的做法是对这个字段定义getXXX和setXXX方法,然后拦截方法,进行相应的操作。
太多的方面?
也许你会认为AOP实在是太强大了,可以到处使用,从而设计出太多的方面,以至于当一个方法被调用时,都难以说清楚究竟执行了哪些代码。
这是很可怕的,“过犹不及”,这是典型的过度设计的毛病。通常情况下,很少有一个对象实例需要5个方面以上。况且过多的方面会影响性能。
在设计的时候,通常如下情况会设计成方面:
(1)大部分模块都需要使用的通用功能,包括系统级或模块级的功能
(2)预计目前的实现,在今后进行功能扩展的可能性很大的地方
正交性
如果多个方面互相影响,造成一些无法预测的结果,该怎么办?多个切入点的功能实现叠加起来,甚至造成错误?
对于这种情况,在设计AOP的时候要特别注意,要遵循连接点的正交模型:不同种类的连接点和不同种类的实现应该能够以任何顺序组合使用。
换句话说,请保持你设计的方面的独立性,功能实现的独立性,不依赖于多个方面的执行先后顺序。
对粗粒度对象使用AOP
AOP通常用来对粗粒度的对象进行功能增强,比如对业务逻辑对象,拦截某个业务方法,进行功能增强,从而提高系统的可扩展性。
注意不要在细粒度的对象上使用AOP,比如对某个实体描述对象。在运行时,这种细粒度对象通常实例很多,比如可能有多条数据,这种情况下,使用AOP,会有大量的方法拦截带来的反射处理,严重影响性能。
视频配套PPT,视频地址【 Spring3开发实战-独家视频课程 】
评论
2 楼
jinnianshilongnian
2012-08-04
kjj 写道
其实spring的aop就是把开源软件aspectj 包装了一下,其中语法啥的都一模一样的
spring使用aspectj的部分功能
1 楼
kjj
2012-08-04
其实spring的aop就是把开源软件aspectj 包装了一下,其中语法啥的都一模一样的
发表评论
-
Struts2+Spring3+Hibernate3整合
2012-08-14 08:20 1717准备三个框架结合的lib包 Spring3结合Stru ... -
Spring中的事务
2012-08-14 08:19 1210更简单的方式是使用@Transactional ... -
Spring3开发实战 之 第五章:Spring中的事务
2012-08-13 13:25 1024Spring框架引人注目的重要因素之一是它 ... -
Spring3开发实战 之 第二章:IoC/DI开发(1)
2012-08-13 13:24 0IoC——Inversion of Control, ... -
Spring3开发实战 之 第四章:对JDBC和ORM的支持
2012-08-06 09:46 974简介 Spring提供的DAO(数据访问对象)支持主要 ... -
Spring3开发实战 之 第三章:AOP开发(1)
2012-08-04 06:13 1252AOP是什么(Aspect Oriented ... -
Spring3开发实战 之 第二章:IoC/DI开发(2)
2012-08-03 12:06 941通过<list/>、<set/> ... -
Spring3开发实战 之 第二章:IoC/DI开发(2)
2012-08-03 10:38 22通过<list/>、<set/> ... -
Spring3开发实战 之 第二章:IoC/DI开发(1)
2012-08-02 12:10 1526IoC——Inversion of Control, ... -
Spring3开发实战 之 第二章:IoC/DI开发(2)
2012-08-01 20:05 127通过<list/>、<set/ ... -
Spring3开发实战 之 第二章:IoC/DI开发(1)
2012-08-01 16:14 59IoC——Inversion of Cont ... -
Spring3开发实战 之 第二章:IoC/DI开发(1)
2012-08-01 16:14 7IoC——Inversion of Cont ... -
Spring3开发实战 之 第二章:IoC/DI开发(1)
2012-08-01 13:02 31IoC——Inversion of Cont ... -
Spring3开发实战 之 第一章:Spring入门
2012-07-30 21:13 1282认识Spring Spring是什么 Sprin ... -
Spring3开发实战 之 第一章:Spring入门
2012-07-30 16:57 45认识Spring Spring是什 ... -
Spring3开发实战 之 第一章:Spring入门
2012-07-30 15:23 62认识Spring Spring是什么 Sprin ...
相关推荐
第3章:讲解Spring IoC容器的知识,通过具体的实例详细地讲解IoC概念。同时,对Spring框架的三个最重要的框架级接口进行了剖析,并对Bean的生命周期进行讲解。 第4章:讲解如何在Spring配置文件中使用Spring 3.0...
《Spring3开发实战》这本书是针对Java开发者,特别是对Spring框架感兴趣...阅读压缩包中的PDF文件,如Spring3PPT(IoC部分).pdf、Spring3PPT(第三部分).pdf、Spring3PPT(AOP部分).pdf,将进一步深入理解这些概念和实践。
在本节"Spring5 实战 第三章3.1代码"中,我们将深入探讨Spring框架的核心概念和在实际开发中的应用。Spring是一个广泛使用的Java企业级应用开发框架,以其依赖注入(Dependency Injection, DI)和面向切面编程...
根据提供的文件信息,可以推断出您所询问的是关于《Spring 3.x 企业应用开发实战》这本书的内容。该书是关于Spring框架的一个实用指南,主要面向那些需要在企业级环境中使用Spring进行应用程序开发的Java开发者。...
在这个上下文中,"Spring 3.x"指的是Spring框架的第三个主要版本,它在2010年发布,包含了许多重要的改进和增强,例如对Java配置的支持、AOP(面向切面编程)的改进以及与Hibernate等其他框架的集成优化。...
2. **第3章**:Spring配置,讲解了XML和注解配置方式,以及如何使用Bean定义和自动装配。 3. **第4章**:依赖注入,深入讨论了DI机制,如何管理对象间的依赖关系,以及如何通过构造器、setter方法和接口实现DI。 4...
第3章:讲解Spring IoC容器的知识,通过具体的实例详细地讲解IoC概念。同时,对Spring框架的三个最重要的框架级接口进行了剖析,并对Bean的生命周期进行讲解。 第4章:讲解如何在Spring配置文件中使用Spring ...
在本章"第3章【源码】java web整合开发实战--基于struts 2+hibernate+spring"中,我们将深入探讨如何在Java Web应用程序中集成三个关键的开源框架:Struts 2、Hibernate和Spring。这些框架分别负责控制层、持久层和...
《Spring 3.x企业应用开发实战》是一本深入讲解Spring框架在实际企业环境中应用的书籍。光盘源码是该书配套的实践材料,旨在帮助读者通过实例加深对Spring 3.x版本的理解和掌握。虽然由于文件大小限制,光盘中的jar...
在本资源中,"Spring 3.x企业应用开发实战光盘源码part02" 提供了Spring框架3.x版本的企业级应用开发实例代码。这部分是整个教程源码的第二部分,暗示着可能存在一个第一部分,可能包含了基础的设置和初始化工作。...
《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练...
总之,这个实战项目旨在帮助开发者掌握Java Web开发中的核心技术栈,通过Struts 2、Hibernate和Spring的整合,提升项目的开发效率和代码质量。通过深入学习和实践,开发者可以更好地应对复杂的企业级应用开发挑战。
10. **Spring与第三方库集成**:Spring的强大之处在于其高度的可扩展性和与其他库的兼容性。本章可能提到了Spring与缓存系统(如 EhCache)、消息中间件(如ActiveMQ)或其他服务(如RESTful API)的集成。 以上...
在"第3章 Spring基本用法.ppt"中,你将学习到如何使用Spring管理Bean,理解IoC容器的工作原理,并通过配置文件或注解来实现依赖注入。而"第4章 面向切面编程.ppt"则深入讲解了AOP,这是Spring中一个强大的功能,允许...
《Spring 3.x 企业应用实战开发-源码》是一份深入探讨Spring框架在实际企业应用中的实践指南,其中包含了从第二章到第十九章的完整源代码。这份资料是学习和理解Spring 3.x核心特性和实际应用场景的宝贵资源。下面...
Struts 2、Hibernate 和 Spring 是Java Web开发中三大核心框架,它们分别负责表现层、持久层和业务层的管理。这本由蒲子明编著的《Struts 2+Hibernate+Spring整合开发技术详解》深入探讨了如何将这三个框架有效结合...
Spring-context-support是为了支持第三方库集成到Spring应用程序上下文中;Spring-expression模块提供了一个强大的表达式语言,用于在运行时查询和操作对象图。 其次,文档也提到了如何学习和查阅Spring的API文档。...
在Spring 3.x企业应用开发实战中,使用到的各种jar包是实现高效、灵活和可扩展的应用程序架构的关键。这些库提供了丰富的功能,包括依赖注入、面向切面编程、数据持久化、Web MVC以及与其他技术的集成。以下是这些...
《Spring3.x企业应用开发实战》是一本深受开发者欢迎的技术书籍,其提供的源代码涵盖了Spring框架在企业级应用中的各种实际应用场景。通过分析这些源代码,我们可以深入理解Spring框架的核心特性和最佳实践。 首先...
《Spring实战第四版》是Java开发领域中一本深入讲解Spring框架的经典著作,源代码的提供为读者提供了亲自动手实践的机会,有助于加深理解和应用。在这个压缩包中,包含的文件名为"spring4源码_Code4",我们可以推测...