Recently, when using spring aop in our project, we fail to intercept the targeted method, so we come up with a checklist for use, as following shows.
CheckList
Web.xml
: Spring Starting Point
The first thing we need to check is the web.xml
, this is where spring is initialized and loaded into your web application.
By configure listener of application, spring custom log4j initialization (Log4jConfigListener
) and init itself (ContextLoaderListener
). By setting spring dispatch servlet, spring load the config file of spring mvc, beans, aop etc, then mapping all web application to dispatcher, which enable spring mvc works.
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:config/spring/common/appcontext-*.xml,
classpath*:config/spring/local/midas-shopdiyaccount-*.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Config File Location
What should be noticed is the value of context config location should match the location of your spring config file, otherwise, your config will not be loaded by spring and not working.
Component Scan and Annotations
If you want to use annotations to mark your beans, you need to set component in xml config file, otherwise your bean will not be registered.
<context:component-scan base-package="com.zzt.learnspring.service"/>
Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Spring-provided @Component, @Repository, @Service, and @Controller stereotypes will be detected. Note: This tag implies the effects of the 'annotation-config' tag, activating @Required, @Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit annotations in the component classes
Enable AOP
If you need spring aop, you need enable it:
<aop:aspectj-autoproxy/>
With the AspectJ support enabled, any bean defined in your application context with a class that is an AspectJ aspect (has the @Aspect
annotation) will be automatically detected by Spring and used to configure Spring AOP
Aspect Register
In order to register your advice you can use @Aspect
plus one of the following
- bean in xml
- @Component with component scan
Public in Method Signature
From Spring AOP - Supported Pointcut Designators
any given pointcut will be matched against public methods only!
Spring aop can only intercept public method, so if your method is not public, spring aop will not work.
AOP with Arguments:
Following is an example of how aop with argument binding should write:
@Around(
value = "execution(public * com.xxx.AdAccountDao+.deleteAccount(int, int)) && args(innerAccountId, operatorId)",
argNames = "pjp,innerAccountId,operatorId"
)
public Object deleteId(ProceedingJoinPoint pjp, int innerAccountId, int operatorId) {
This kind of aop can sometimes ease the work of cast, but also make the advice binding just one method. If this method interface changed in the future, this execution expression also need updates.
Method Signature: long
and Long
One more thing that need attention is your method parameter type should be exact: long
and Long
are different. If your method use primitive type and your advice use boxing type, spring aop will not match this advice.
Order
If your spring aop still not work, you may try to set your aspect a higher order like following:
@Aspect
@Order(1)
public class LogAspect {}
This actually make your advice is executed first if the targeted pointcut has more than one advice. We have met the situation where the earlier advice (implemented by IntroductionInterceptor
) just return the result rather than call the latter advice then return. So letting our advice execute first can solve this problem.
Debug
You may set breakpoint in the following spring method, where you can see the order of advice for a specific method.
public class AdvisedSupport extends ProxyConfig implements Advised {
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {}
Misunderstanding
Handler Interceptor vs Spring AOP
As this SO question clarified, they have different granularity:
- handler interceptor is for request
- aop is for method
Public in Execution Expression
From spring aop:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
the modifiers for method is optional, which will not affect the pointcut matching. In other word, the public in expression can be omitted.
CGLIB vs Proxy
From proxying mechnism:
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.
Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces
Ref
Written with StackEdit.
评论
发表评论