AOP: Aspect Oriented Programming

[b]The AspectJ Programming Guide:
[url]http://www.eclipse.org/aspectj/doc/next/progguide/index.html[/url]


Spring ref 9 - Aspect Oriented Programming with Spring:
[url]http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html[/url][/b][quote][b][color=red]CORE concepts:[/color][/b]
[b]Aspect:[/b] a modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in enterprise Java applications. In Spring AOP, aspects are implemented using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJ style).
[b]Join point:[/b] a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.
[b]Advice:[/b] action taken by an aspect at a particular join point. Different types of advice include "around," "before" and "after" advice. (Advice types are discussed below.) Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors around the join point.
[b]Pointcut:[/b] 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, and Spring uses the AspectJ pointcut expression language by default.
[b]Introduction:[/b] declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)
[b]Target object:[/b] object being advised by one or more aspects. Also referred to as the advised object. Since Spring AOP is implemented using runtime proxies, this object will always be a proxied object.
[b]AOP proxy:[/b] an object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a CGLIB proxy.
[b]Weaving:[/b] linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime.
[color=red][b]Types of advice:[/b][/color]
[b]Before advice:[/b] Advice that executes before a join point, but which does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception).
[b]After returning advice:[/b] Advice to be executed after a join point completes normally: for example, if a method returns without throwing an exception.
[b]After throwing advice:[/b] Advice to be executed if a method exits by throwing an exception.
[b]After (finally) advice:[/b] Advice to be executed regardless of the means by which a join point exits (normal or exceptional return).
[b]Around advice:[/b] Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception.[/quote]
关于 advice types 的不错解释:
[url]http://stackoverflow.com/questions/12643620/throwing-exceptions-in-spring-aop[/url][quote]try {
//@Before
method();
//@AfterReturning
} catch(Throwable t) {
//@AfterThrowing
} finally {
//@After
}[/quote]

Spring AOP是基于Proxy的,所以无法拦截内部方法调用(internal method call),即下面的对Service.b()的intercept是不起作用的:(google key words:spring aop internal method call)

@Component
@Aspect
public class Advice {
@Around("execution(* somePackages.Service.b(..))")
public Object swallowThrowing(ProceedingJoinPoint pjp) {
try {
return pjp.proceed();
} catch (Throwable e) {
//do something
}
}

public class Service {
public void a() {
b(); //equivalent to this.b(); any call to "this" from within your service instance is directly invoked on that instance and cannot be intercepted by the wrapping proxy (the proxy is not even aware of any such call)
}

public void b() {
}
}
想要拦截内部方法调用请使用aspectJ的load-time weaving(或者compile time weaving?)。
SPring aop ref 9.6.1 Understanding AOP proxies:
[b][url]http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies[/url][/b]
Spring AOP top problem #1 - aspects are not applied:
[b][url]http://denis-zhdanov.blogspot.com/2009/07/spring-aop-top-problem-1-aspects-are.html[/url][/b]
[url]http://stackoverflow.com/questions/14111422/spring-aop-does-not-intercept-methods-within-springs-container[/url]
[url]http://stackoverflow.com/questions/7338760/spring-aop-intercepting-calls-from-within-the-same-service-class[/url][quote][b]Once inside a class instance, any method-calls to methods in the same instance will be directly against the actual instance object, not the wrapping proxy so AOP advices will not be considered.[/b][/quote]


[b]在任意地方(特指不被spring管理、无法获取到ApplicationContext的地方) new 另外一个新的对象,并为 new 出的对象注入 Spring bean:[/b]
[url]http://stackoverflow.com/questions/11755152/spring-instrument-and-auto-injection-in-new-object[/url]
Injection on new-created objects (rather than managed beans) is only possible with compile- or load-time weaving, not with the run-time proxies that Spring uses by default.[quote][b][color=red]1 [/color]load-time weaving:[/b]
[url]http://stackoverflow.com/questions/4703206/spring-autowiring-using-configurable[/url]
需要注入的类上写上 @Configurable / @Autowired:

//new BackgroundFactory(), 则 由 spring ioc 管理的 UserService 实例会自动被注入进来
@Configurable(preConstruction=true, autowire=Autowire.BY_NAME,dependencyCheck=true)
public class BackgroundFactory implements Factory<List<Background>> {

private static final Logger logger = LoggerFactory.getLogger(BackgroundFactory.class);

@Autowired
private UserService userService;

@Override
public List<Background> create(Integer userId) {
List<Background> backgrounds = userService.findBackgroundsByUserId(userId);
return backgrounds;
}

public UserService getUserService() {
return userService;
}

public void setUserService(UserService userService) {
this.userService = userService;
}

}
applicationContext.xml 中:

<context:spring-configured/>
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/>
<context:component-scan base-package="。。。" />
在tomcat 中需要做的(否则会报 [i][size=xx-small][org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method[/size][/i],参见:[url]http://stackoverflow.com/questions/14176417/spring-maven-project-beancreationexception[/url] [url]http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-aj-ltw-environments[/url]):[quote]1 copy org.springframework.instrument.tomcat.jar into $CATALINA_HOME/lib;
2 tomcat 的 server.xml 中为 Context 标签指定 spring 的 Loader:

<Context docBase="xxx-webapp" path="/xxx-webapp" reloadable="true" source="org.eclipse.jst.jee.server:xxx-webapp">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
[/quote]Maven depen:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
load-time weaving时,spring xml 中 <context:spring-configured/> 和 <context:load-time-weaver /> 两个标签都可以用各自对应的注解 @EnableSpringConfigured 和 @EnableLoadTimeWeaving 来替代,即:移除 spring xml 中这两个标签,而在 BackgroundFactory 类上使用 @EnableSpringConfigured 和 @EnableLoadTimeWeaving:

//new BackgroundFactory(), 则 由 spring ioc 管理的 UserService 实例会自动被注入进来
@EnableSpringConfigured
@EnableLoadTimeWeaving(...)
@Configurable(preConstruction=true, autowire=Autowire.BY_NAME,dependencyCheck=true)
public class BackgroundFactory implements Factory<List<Background>> {
...
[b]但需要说明的是,Compile-time weaving 时,不能用 @EnableSpringConfigured!必须是在xml中用 <context:spring-configured/>!@EnableSpringConfigured 这个注解只适用于和 @EnableLoadTimeWeaving 配合使用的 load-time weaving 的情况![/b]
[b][color=red]2 [/color]Compile-time weaving[/b]
因为是在编译时织入,所以如果你是用maven来做项目的build的,则需要在项目的 pom.xml 中为项目添加编译时的aspectj支持:

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<complianceLevel>1.6</complianceLevel>
<Xlint>ignore</Xlint>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

</project>
你应该有些奇怪这里为什么要依赖 persistence-api;这是 spring-aspects 的一个bug;如果不引入persistence-api依赖,则在 m2e 下会报 [size=xx-small][i]can't determine annotations of missing type javax.persistence.Entity[/i][/size](最开始我在 m2e 和 mvn 下都报这个错,但后来在不依赖 persistence-api 的情况下 mvn 不报这个错了,m2e 还是报;有些奇怪,尚未搞清楚为什么)。详见:
[url]http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html[/url]
[url]https://jira.springsource.org/browse/SPR-6819[/url]
spring applicatonContext.xml 中:

<!-- 如上所说,这里只能用<context:spring-configured />的方式,而不能使用@EnableSpringConfigured -->
<context:spring-configured />
<context:component-scan base-package="。。。" />
BackgroundFactory 类跟上面的一样,添加 @Configurable & @Autowired 注解即可:

//new BackgroundFactory(), 则 由 spring ioc 管理的 UserService 实例会自动被注入进来
@Configurable(preConstruction=true, autowire=Autowire.BY_NAME, dependencyCheck=true)
public class BackgroundFactory implements Factory<List<Background>> {

private static final Logger logger = LoggerFactory.getLogger(BackgroundFactory.class);

@Autowired
private UserService userService;
。。。
如果你在eclipse中使用了m2e,会发现m2e无法识别aspectj-maven-plugin这个plugin的 <execution>,会报错误 [i][size=xx-small]Plugin execution not covered by lifecycle configuration: org.codehaus.mojo:aspectj-maven-plugin:1.4:compile (execution: default, phase: compile)[/size][/i];这是因为你的eclipse中尚未安装 m2t 的 AJDT Connector,参考这里安装即可:
[url]http://stackoverflow.com/questions/6522540/maven-ajdt-project-in-eclipse[/url][quote]Step1:install AJDT(AspectJ development tools) in eclipse
Step2: install "AJDT m2e Configurator", repo url:http://dist.springsource.org/release/AJDT/configurator/[/quote][/quote]总结:Load-time weaving 因为是在类加载时织入,所以如果是在web war项目,则需要 web container 支持 Load-time weaving 才行;如果如上面的 tomcat 的例子一样,其本身不支持,则需要改变其依赖的lib和server.xml,这在 prod env 下很可能不是你能决定的,所以,首选 Compile-time weaving。
另外,如果你是在一个可获取到 ApplicationContext 的 spring bean 中 new 一个对象,并想将一些依赖注给该new出的对象,可以使用 AutowireCapableBeanFactory:
[url]http://stackoverflow.com/questions/3813588/how-to-inject-dependencies-into-a-self-instantiated-object-in-spring[/url]
[url]http://stackoverflow.com/questions/3693971/can-i-inject-a-java-object-using-spring-without-any-xml-configuration-files[/url]
[url]http://stackoverflow.com/questions/129207/getting-spring-application-context[/url]


good stuffs:
Spring AOP: Dynamic Proxies vs. CGLib proxies:
[url]http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html[/url]
一个 After Throwing Advice 的例子:
[url]http://www.captaindebug.com/2011/09/using-aspectjs-afterthrowing-advice-in.html#.UOjMtbTMh1N[/url]
Logging Standard Exceptions with Spring AOP:
[url]http://tech.tejusparikh.com/post/10920309943/logging-standard-exceptions-with-spring-aop[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值