跳至主要内容

Spring Config Checklist

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.

评论

此博客中的热门博文

Spring Boot: Customize Environment

Spring Boot: Customize Environment Environment variable is a very commonly used feature in daily programming: used in init script used in startup configuration used by logging etc In Spring Boot, all environment variables are a part of properties in Spring context and managed by Environment abstraction. Because Spring Boot can handle the parse of configuration files, when we want to implement a project which uses yml file as a separate config file, we choose the Spring Boot. The following is the problems we met when we implementing the parse of yml file and it is recorded for future reader. Bind to Class Property values can be injected directly into your beans using the @Value annotation, accessed via Spring’s Environment abstraction or bound to structured objects via @ConfigurationProperties. As the document says, there exists three ways to access properties in *.properties or *.yml : @Value : access single value Environment : can access multi

Elasticsearch: Join and SubQuery

Elasticsearch: Join and SubQuery Tony was bothered by the recent change of search engine requirement: they want the functionality of SQL-like join in Elasticsearch! “They are crazy! How can they think like that. Didn’t they understand that Elasticsearch is kind-of NoSQL 1 in which every index should be independent and self-contained? In this way, every index can work independently and scale as they like without considering other indexes, so the performance can boost. Following this design principle, Elasticsearch has little related supports.” Tony thought, after listening their requirements. Leader notice tony’s unwillingness and said, “Maybe it is hard to do, but the requirement is reasonable. We need to search person by his friends, didn’t we? What’s more, the harder to implement, the more you can learn from it, right?” Tony thought leader’s word does make sense so he set out to do the related implementations Application-Side Join “The first implementation

Implement isdigit

It is seems very easy to implement c library function isdigit , but for a library code, performance is very important. So we will try to implement it and make it faster. Function So, first we make it right. int isdigit ( char c) { return c >= '0' && c <= '9' ; } Improvements One – Macro When it comes to performance for c code, macro can always be tried. #define isdigit (c) c >= '0' && c <= '9' Two – Table Upper version use two comparison and one logical operation, but we can do better with more space: # define isdigit(c) table[c] This works and faster, but somewhat wasteful. We need only one bit to represent true or false, but we use a int. So what to do? There are many similar functions like isalpha(), isupper ... in c header file, so we can combine them into one int and get result by table[c]&SOME_BIT , which is what source do. Source code of ctype.h : # define _ISbit(bit) (1 << (