Возможно ли иметь экземпляр аспекта для pointcut?Spring AOP и Aspect «perthis»
Я хочу реализовать простой прокси-сервер 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). –
вы должны добавить соответствующие теги – emotionlessbananas