是否可以为每个切入点设置方面实例?
我想实现简单的基于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()
}
}
答案 0 :(得分:0)
微米。 Deinum 是对的。正如Spring AOP manual中所述,Spring AOP不支持可能对您有所帮助的实例化模型percflow()
和percflowbelow()
。
但是每个对象甚至每个连接点的一个方面实例无论如何都是昂贵的。为什么不使用类似于here提到的缓存方法?在那个答案中,我只是重复使用原始海报的方法,回答关于单元测试方面的另一类问题,我认为它可以以更智能的方式实现,但基本上它可以工作,你很容易理解它是如何完成的。
P.S。:我也喜欢用Spock进行测试。凉! :-)我完全停止使用JUnit,除了我正在回答我刚刚指出的问题的情况。