首次使用后注入Aspect中的字段,在启动时导致NullPointerException

时间:2016-04-08 11:45:35

标签: java spring spring-mvc aop spring-aop

摘要:

我在@PostConstruct @Service ServiceInitialiserFacsimile执行了一些初始化操作。这些操作包括在执行方法(DoAttionalStuffAspect)之后调用方法。

Aspect通过aspectOf即时显示,因此它由Spring容器处理,但不幸的是,它的依赖关系被注入 AFTER ServiceInitialiserFacsimile @PostConstruct的执行,导致NullPointerException。

如何告诉Spring容器首先注入Aspect中的字段然后实例化ServiceInitialiserFacsimile

我尝试使用Autowired构造函数来表示方面,但我认为最终AspectJ需要no-arg构造函数,所以没有帮助

CODE

这是我为了重现我在一个更复杂的应用程序中遇到的问题而创建的示例。如果您想查看它,这是项目。 https://github.com/alessiop86/spring3-mvc-maven-xml-hello-world

以下代码: 这是初始化类:

@Component
public class ServiceInitialiserFacsimile {

    private final SampleService sampleService;

    @Autowired
    public ServiceInitialiserFacsimile(SampleService ss) {
        this.sampleService = ss;
    }

    @PostConstruct
    public void initialiseAllTheServices() {
        this.sampleService.init();
    }

}

这是具有某些自定义逻辑的服务,需要由ServiceInitialiserFacsimile @PostConstruct进行初始化:

@Service
public class SampleService {

    public void init() {
        System.out.println("do some stuff");
        try {
            execute();
        }
        catch(Exception e) {
            System.err.println("I do not want to block to whole framework initialisation");
        }
    }

    @DoAdditionalStuff
    public void execute() {
        System.out.println("Phase 1");
    }
}

这是我在方面定义中使用的注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoAdditionalStuff {
}

这是方面

@Aspect
public class AdditionalStuffAspect {

    private AdditionalStuffService service;

    public AdditionalStuffService getService() {
        return service;
    }

    public void setService(AdditionalStuffService service) {
        this.service = service;
    }

    @Pointcut(value="execution(public * *(..))")
    private void anyPublicMethod() { }

    @AfterReturning("anyPublicMethod() && @annotation(doAdditionalStuff)")
    public void afterReturning(JoinPoint jointPoint, DoAdditionalStuff doAdditionalStuff) {
        System.out.println(jointPoint);
        service.doStuff();
    }
}

这是创建的服务,但在运行方面时尚未实例化:

@Service
public class AdditionalStuffService {

    public void doStuff() {
        System.out.println("Phase2: additional stuff");
    }
}

Spring context xml配置文件:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <context:component-scan base-package="initialisation.mess"/>

    <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/jsp/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <mvc:resources mapping="/resources/**" location="/resources/"/>

    <mvc:annotation-driven/>

    <bean class="initialisation.mess.aspects.AdditionalStuffAspect" factory-method="aspectOf">
        <property name="service" ref="additionalStuffService" />
    </bean>
</beans>

1 个答案:

答案 0 :(得分:0)

通过在xml中设置id,我能够从Aspect强制执行对ServiceInitialiserFacsimile的依赖:

  <bean id="myAspect" class="initialisation.mess.aspects.AdditionalStuffAspect" factory-method="aspectOf">
        <property name="service" ref="additionalStuffService" />
    </bean>

然后使用ServiceInitialiserFacsimile注释指定弹簧托管AdditionalStuffAspect@DependsOn的依赖关系:

@Component
@DependsOn("myAspect")
public class ServiceInitialiserFacsimile {

    private final SampleService sampleService;

    @Autowired
    public ServiceInitialiserFacsimile(SampleService ss) {
        this.sampleService = ss;
    }

    @PostConstruct
    public void initialiseAllTheServices() {
        this.sampleService.init();
    }

}