1. Introduction
In this post, I would demo how to solve error Type referred to is not an annotation type when using Spring AOP.
2. Environment
SpringBoot 2
java 1.8+
AspectJ Tools 1.9.4
3. The POM
We only use the SpringBoot 2 and AspectJ 1.9.4 , the POM is as follows:
<dependencies>
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId> spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId> org.aspectj</groupId>
<artifactId> aspectjtools</artifactId>
<version> 1.9.4</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId> org.springframework.boot</groupId>
<artifactId> spring-boot-dependencies</artifactId>
<version> 2.0.2.RELEASE</version>
<type> pom</type>
<scope> import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4. The Code
We want to use Spring AOP to add logging ability to SpringBoot web controllers, the code is as follows:
The Controller :
package com . bswen . testspringaop . controllers ;
import org.springframework.stereotype.Controller ;
import org.springframework.web.bind.annotation.RequestMapping ;
import org.springframework.web.bind.annotation.ResponseBody ;
@Controller
public class HelloController {
@RequestMapping ( value = "hello" )
public @ResponseBody String getHello () {
try {
Thread . sleep ( 1000 );
} catch ( InterruptedException e ) {
e . printStackTrace ();
}
return "hello" ;
}
}
You can see that, this controller just simply returns a string, the url is http://localhost:8080/hello
The Spring AOP Aspect :
import org.aspectj.lang.ProceedingJoinPoint ;
import org.aspectj.lang.annotation.Around ;
import org.aspectj.lang.annotation.Aspect ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.stereotype.Component ;
@Aspect
@Component
public class MyConrollerLogger {
private static Logger logger = LoggerFactory . getLogger ( MyConrollerLogger . class );
@Around ( "@within(com.bswen.testspringaop.controllers.HelloController)" ) // we want HelloController to be instrumented
public void logAround ( ProceedingJoinPoint pjp ) throws Throwable {
long start = System . nanoTime ();
Object retval = pjp . proceed ();
long end = System . nanoTime ();
String methodName = pjp . getSignature (). getName ();
logger . info ( "Execution of " + methodName + " took " +
TimeUnit . NANOSECONDS . toMillis ( end - start ) + " ms" );
}
}
Run the code, we got the error message:
2019-07-06 22:54:40.012 WARN 22494 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat': Initialization of bean failed; nested exception is **java.lang.IllegalArgumentException: error Type referred to is not an annotation type: com.bswen.testspringaop.controllers.HelloController**
2019-07-06 22:54:40.024 INFO 22494 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-07-06 22:54:40.039 ERROR 22494 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error Type referred to is not an annotation type: com.bswen.testspringaop.controllers.HelloController
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:155) ~[spring-boot-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.0.6.RELEASE.jar:5.0.6.RELEASE]
5.Why did this error happen?
we had this error because we misused the Within expression,according to spring aop documents , When we define the pointcut by using within, there are following usages examples:
any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
any join point (method execution only in Spring AOP) within the service package or a sub-package:
within(com.xyz.service..*)
any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:
@within(org.springframework.transaction.annotation.Transactional)
Here we used the Within like this:
@Around(“within(@com.bswen.testspringaop.controllers.HelloController *)”)
It would let spring to find the class with annotation @HelloController, and because no class is annoatated by it, so there is an error.
6.How to solve this problem?
We should change the pointcut expression to this:
@Around ( "within(com.bswen.testspringaop.controllers.*)" )
This means any class under com.bswen.testspringaop.controllers package should be instrumented.
Run the code, we get this:
2019-07-06 23:29:09.443 INFO 22579 --- [nio-8080-exec-1] c.b.t.aspects.MyConrollerLogger : Execution of getHello took 1007 ms
6. Summary
Be careful if you want to use Within in spring aop pointcut expressions.