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

Java 第一次使用后注入Aspect中的字段,在启动时导致NullPointerException,java,spring,spring-mvc,aop,spring-aop,Java,Spring,Spring Mvc,Aop,Spring Aop,摘要: 我在@Service的@PostConstruct中执行了一些初始化操作。这些操作包括对方法的调用,在该方法执行后,将应用一个方面(DoAttionalStuffAspect) Aspect是通过aspectOf实例化的,因此它由Spring容器处理,但不幸的是,它的依赖项在执行ServiceInitializerFax@PostConstruct后被注入,导致NullPointerException 如何告诉Spring容器首先在方面中注入字段,然后实例化ServiceInitiali

摘要:

我在
@Service
@PostConstruct
中执行了一些初始化操作。这些操作包括对方法的调用,在该方法执行后,将应用一个方面(
DoAttionalStuffAspect

Aspect是通过aspectOf实例化的,因此它由Spring容器处理,但不幸的是,它的依赖项在执行ServiceInitializerFax
@PostConstruct
后被注入,导致NullPointerException

如何告诉Spring容器首先在方面中注入字段,然后实例化
ServiceInitializerFax

我尝试了一个方面的自动连接构造函数,但我认为最终AspectJ需要无参数构造函数,因此没有帮助

代码

这是我创建的一个示例,目的是在一个更复杂的应用程序中重现我遇到的问题。这是你想要查看的项目

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

@Component
public class ServiceInitialiserFacsimile {

    private final SampleService sampleService;

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

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

}
这是具有某些自定义逻辑的服务,需要由
服务初始化器传真
@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上下文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>

/WEB-INF/views/jsp/
.jsp

通过在xml中设置id,我能够从方面强制ServiceInitializerFax的依赖性:

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

如果您使用的是基本SpringAOP,那么它将永远不会工作。代理尚未创建,因此尚未应用AOP,除此之外,如果它是代理,它仍然无法工作,因为它是一个内部方法调用,并且不会通过代理。如果您使用LTW或CTW,并且由Spring管理方面,Spring如何知道注入什么。。。注入方面没有
@Autowired
。@M.Deinum很抱歉,我忘了将xml添加到问题中(它在github上提供,我也将在此处添加)。我使用xml配置进行依赖项注入,因为我正在复制我必须更新的更大项目的代码库。问题不在于方面不起作用或依赖项注入不起作用。一切都在运行,但执行顺序是错误的。如果没有出现错误,你的方面是编织在一起的,所以它会在需要时执行,因为没有明确的顺序(spring可以检测到!)你必须自己指定它,在需要方面的每个bean上添加一个
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();
    }

}