[JAVA] ProxyFactory is convenient when you want to test AOP in Spring!

Overview

--I want to test if the AOP settings are working ――However, it is difficult to test if you are performing processing that causes side effects to the outside (eg transaction, log output ... etc). --Proxy Factory is convenient in such a case

First, write a normal test code

Prepare the following Service class and MethodInterceptor as a prerequisite.

AOP target Service


@Service
class SampleService {
    fun execute() {
        println("SampleService#execute")
    }
}

Interceptor


class SampleInterceptor(
        private val name: String
) : MethodInterceptor {
    override fun invoke(invocation: MethodInvocation?): Any? {
        println("intercept by $name")
        return invocation?.proceed()
    }
}

class SampleServicePointCut : StaticMethodMatcherPointcut() {
    override fun matches(method: Method, @Nullable targetClass: Class<*>?): Boolean {
        return targetClass?.let { SampleService::class.java.isAssignableFrom(it) } ?: false
    }
}

config


@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
class AopConfig {

    @Bean
    fun interceptorA(): Advisor {
        return DefaultPointcutAdvisor(SampleServicePointCut(), SampleInterceptor("configured interceptor"))
    }
}

Test code


@SpringBootApplication
class SpringTestApplication

@RunWith(SpringRunner::class)
@SpringBootTest(classes = [SpringTestApplication::class])
internal class SampleServiceTest {
    @Autowired
    private lateinit var service: SampleService

    @Test
    fun test() {
        service.execute()
    }
}

Execution result


intercept by configured interceptor
SampleService#execute

Let's write the test code as follows using ProxyFactory

Test code using ProxyFactory


@Test
fun testByProxy() {
    val factory = ProxyFactory(SampleService())
    factory.addAdvisor(DefaultPointcutAdvisor(SampleServicePointCut(), SampleInterceptor("Proxy")))
    val proxy = factory.proxy as SampleService
    proxy.execute()
}

Execution result


intercept by Proxy
SampleService#execute

Kotlin may create a Util function

It is also good to create a util function using Extension.

Example using kotlin extension Test code using ProxyFactory


@Test
fun testByProxy() {
    val proxy = SampleService().proxy {
        addAdvisor(DefaultPointcutAdvisor(SampleServicePointCut(), SampleInterceptor("Proxy")))
    }
    proxy.execute()
}

@Suppress("UNCHECKED_CAST")
fun <T : Any> T.proxy(settings: ProxyFactory.() -> Unit): T {
    return ProxyFactory(this).also { settings(it) }.proxy as T
}

AspectJProxyFactory if using @Aspect

Service and Config


@Aspect
@Component
class SampleAspect(
        private val name: String = ""
) {
    @Before("execution(* SampleAspectService.*(..))")
    fun advice() {
        println("advice by $name")
    }
}

@Service
class SampleAspectService {
    fun execute() {
        println("SampleAspectService#execute")
    }
}

Test code


@Test
fun testAspectProxy() {
    val factory = AspectJProxyFactory(SampleAspectService())
    factory.addAspect(SampleAspect("proxy"))
    val proxy = factory.getProxy() as SampleAspectService
    proxy.execute()
}

Execution result


advice by proxy
SampleAspectService#execute

Recommended Posts

ProxyFactory is convenient when you want to test AOP in Spring!
Delegate is convenient to use when you want to reuse parts
When you want to bind InputStream in JDBI3
[RSpec] When you want to use the instance variable of the controller in the test [assigns is not recommended]
When you want to notify an error somewhere when using graphql-spring-boot in Spring Boot
When you want to dynamically replace Annotation in Java8
How to unit test Spring AOP
Things to note when using Spring AOP in Jersery resource classes
What to do when you want to know the source position where the method is defined in binding.pry
A note when you want Tuple in Java
When you want to use the method outside
[Swift] Use nonzeroBitCount when you want popcnt in Swift
[Ruby] When you want to replace multiple characters
What to do when you want to delete a migration file that is "NO FILE"
If you want to satisfy the test coverage of private methods in JUnit
I want to use Clojure's convenient functions in Kotlin
If you want to separate Spring Boot + Thymeleaf processing
How to test file upload screen in Spring + Selenium
If you want to recreate the instance in cloud9
When Spring Batch is executed continuously in Oracle, ORA-08177
Code to use when you want to process Json with only standard library in Java
How to write in Model class when you want to save binary data in DB with PlayFramework
If you want to make a Java application a Docker image, it is convenient to use jib.
Use JLine when you want to handle keystrokes on the console character by character in Java
When you want to implement Java library testing in Spock with multi-module in Gradle in Android Studio 3
When you want to reflect the Master Branch information in the Current Branch you are currently working on
When there is no output to stdout in docker log
I want to randomly generate information when writing test code
When you want to explicitly write OR or AND with ransack
When you want to change the MySQL password of docker-compose
docker-compose.yml when you want to keep mysql running with docker
lombok.config when you want to pass @Qualifier to @RequiredArgsConstructor with lombok
Introduction to Spring Boot ② ~ AOP ~
[Swift] When you want to know if the number of characters in a String matches a certain number ...
How to write when you want to keep line breaks and output while avoiding XSS in Rails
Object-oriented design that can be used when you want to return a response in form format
How to write when you want to handle "array of C language strings" like argv [] in Ruby-FFI
Throw an exception and catch when there is no handler corresponding to the path in spring
If you just want to run your containers in the cloud, Azure Container Instances is easy
When I try to put centos in VMware, pane is dead
If you want to include the parent class in Lombok's @builder
When you want to ZIP download the image data saved locally
How to output the value when there is an array in the array
Setting that converts to binding.pry when you type pry in VScode
[Docker] Magic command when you want to wipe out none image
When you have introduced devise but want to add more columns
[Spring Boot] Until @Autowired is run in the test class [JUnit5]
Practice to use when you want to execute different processing groups serially
How to write the view when Vue is introduced in Rails?
How to solve the problem that it is not processed normally when nesting beans in Spring Batch
The first thing to do when you want to be happy with Heroku on GitHub with Eclipse in Java
What to do if Operation not permitted is displayed when you execute a command in the terminal
How to use Lombok in Spring
Write test code in Spring Boot
JUnit 5 parameterization test is super convenient
What is @Autowired in Spring boot?
Event processing is performed in Spring.
A memo when you want to clear the time part of the calendar
Spring.messages.fallback-to-system-locale: false is required to default message.properties for i18n support in Spring boot
When you want Rails to disable a session for a specific controller only
Summary of means when you want to communicate with HTTP on Android