【发布时间】:2016-08-18 17:04:39
【问题描述】:
每个切入点是否可以有切面实例?
我想实现简单的基于 Spring AOP 代理的方面。 如果方法标记在单独的类中,perthis 和 pertarget 都可以正常工作。 但是当多个方法应该缓存在一个类中时,我该怎么办?
示例项目:https://github.com/mezlogo/spring-aop-sample
例如,我有:
build.gradle
buildscript {
repositories { jcenter() }
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.5.RELEASE")
}
}
apply plugin: 'spring-boot'
apply plugin: 'groovy'
repositories { jcenter() }
dependencies {
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.6'
compile 'org.springframework.boot:spring-boot-starter-aop'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile group: 'org.spockframework', name: 'spock-spring', version: '1.0-groovy-2.4'
}
CacheAspect.groovy
package mezlogo
import groovy.transform.CompileStatic
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
@CompileStatic
@Aspect("perthis(@annotation(mezlogo.CacheIt))")
class CacheAspect {
int cachedValue = -1
@Around('@annotation(mezlogo.CacheIt)')
int cacheRemoteService(ProceedingJoinPoint pjp) {
if (-1 == cachedValue) {
def result = pjp.proceed()
cachedValue = (int) result
}
cachedValue
}
}
自定义CacheIt.java注解
package mezlogo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheIt{}
Config.groovy
package mezlogo
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.EnableAspectJAutoProxy
import org.springframework.context.annotation.Scope
@Configuration
@EnableAspectJAutoProxy
class Config {
@Bean
RemoteService remoteService() { new RemoteService() }
@Bean
@Scope("prototype")
CacheAspect cacheAspect() { new CacheAspect() }
}
RemoteService.groovy
package mezlogo
import groovy.transform.CompileStatic
@CompileStatic
class RemoteService {
static final int RESULT = 1
static final int ANOTHER_RESULT = 2
static final RuntimeException exception = new RuntimeException('Prevent it by caching')
boolean isFirstAccessed = true
boolean isSecondAccessed = true
@CacheIt
int firstMethod() {
if (!isFirstAccessed) { throw exception }
isFirstAccessed = false
RESULT
}
@CacheIt
int secondMethod() {
if (!isSecondAccessed) { throw exception }
isSecondAccessed = false
ANOTHER_RESULT
}
}
最后,CacheAspectSpec.groovy
package mezlogo
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.SpringApplicationConfiguration
import spock.lang.Specification
import spock.lang.Stepwise
@SpringApplicationConfiguration(Config)
@Stepwise
class CacheAspectSpec extends Specification {
@Autowired
RemoteService sut
def "should cache firstMethod result"() {
expect: "firstMethod return correct result"
sut.firstMethod() == RemoteService.RESULT
when: "firstMethod fired again"
sut.firstMethod()
then: "no RTE has been thrown"
noExceptionThrown()
}
def "should cache secondMethod result"() {
expect: "secondMethod return correct result"
//Cache return RemoteService.RESULT value
sut.secondMethod() == RemoteService.ANOTHER_RESULT
when: "secondMethod fired again"
sut.secondMethod()
then: "no RTE has been thrown"
noExceptionThrown()
}
}
【问题讨论】:
-
简短的回答是不,你不能。扩展的将是顾问的答案,这取决于。您不能使用 Spring AOP,因为它是基于代理的,并且根本无法使用它(它只支持有限的 AspectJ 语言集)。您需要使用本机 Aspectj 并使用编译时编织(也许加载时编织也可以)才能正常工作,因此您需要一个完整的 AspectJ 解决方案,而不是基于代理的解决方案(默认情况下是 Spring AOP)。
-
你必须添加正确的标签
标签: java spring groovy aop spring-aop