Java 在 AspectJ 和 Springboot 中使用 @Autowired
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21350966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using @Autowired with AspectJ and Springboot
提问by maxiplay
I want to use @Autowired annotation into an "Aspect". I want to inject a repository in my aspect but when I try to call a method of my autowired class a NullPointException occurs.
我想将 @Autowired 注释用于“方面”。我想在我的方面注入一个存储库,但是当我尝试调用我的自动装配类的方法时,会发生 NullPointException。
@Aspect
public class AspectSecurity {
@Autowired
private UserRepository userRepository;
@After("execution(public * dash.*.*Controller.*(..))")
public void authentication(JoinPoint jp) throws UnauthorizedException {
System.out.println("SECURITY !");
System.out.println(userRepository.findAll().toString());
}
}
I have already tried to add @Component
above my aspect Class but I have the same error.
我已经尝试@Component
在我的方面类之上添加,但我有同样的错误。
If I don't use an aspect class but a @Controller
I can call my repository without problems.
如果我不使用方面类,但@Controller
我可以毫无问题地调用我的存储库。
Some documentation speak about spring configuration with xml files but with spring boot I don't have these files.
一些文档讨论了带有 xml 文件的 spring 配置,但使用 spring boot 我没有这些文件。
Here a part of my pom.xml wich call the aspectJ plugin:
这是我的 pom.xml 的一部分,它调用了 aspectJ 插件:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>1.6</source>
<target>1.6</target>
<Xlint>ignore</Xlint>
<complianceLevel>${compiler.version}</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>false</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
Here my Application class:
这是我的应用程序类:
package dash;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here the Controller class which the aspect is called:
这里是调用方面的 Controller 类:
package dash.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import dash.GenericController;
@Controller
@RequestMapping("/user")
public class UserController extends GenericController {
@Autowired
private UserRepository repository;
@RequestMapping("/findAll")
public @ResponseBody User create(
@RequestParam(value="login", required=true) String login,
@RequestParam(value="password", required=true) String password) {
System.out.println(login);
System.out.println(password);
System.out.println("Users found with findAll():");
System.out.println("-------------------------------");
for (User user : repository.findAll()) {
System.out.println(user);
}
return repository.findOne("root");
}
}
Note: I have already tried to add @EnableAspectJAutoProxy
above my application class
注意:我已经尝试@EnableAspectJAutoProxy
在我的应用程序类上方添加
thanks for your help
感谢您的帮助
采纳答案by Dave Syer
It's quite tricky to set up AspectJ weaving so a few things could be wrong here. I would suggest that you do notuse @Component
on your @Aspect
(or at least make sure it is excluded from a @ComponentScan
). The reason for that is you have to create a @Bean
of that type and explicitly use the same creation mechanism that AspectJ does, so that Spring and AspectJ agree on the value of the singleton instance. I believe the correct way to do that is to use the static convenience methods in Aspects
in your @Bean
definition. E.g.
设置 AspectJ 编织非常棘手,因此这里可能会出现一些错误。我建议你不使用@Component
你的@Aspect
(或至少确保它是从排除@ComponentScan
)。这样做的原因是您必须创建@Bean
该类型的 a 并显式使用与 AspectJ 相同的创建机制,以便 Spring 和 AspectJ 就单例实例的值达成一致。我相信正确的方法是Aspects
在您的@Bean
定义中使用静态便利方法。例如
@Bean
public AspectSecurity interceptor() {
AspectSecurity aspect = Aspects.aspectOf(AspectSecurity.class);
// ... inject dependencies here if not using @Autowired
return aspect;
}
In addition you will need an aop.xml
to ensure that the compiled aspect is on the AspectJ weaver path. It could be that is what you are doing with the Maven AspectJ plugin, but if it was me doing this I would probably just create an aop.xml
manually, use @EnableLoadTimeWeaving
, and ditch the plugin. You can probably decide yourself based on what works.
此外,您将需要aop.xml
确保已编译的方面位于 AspectJ weaver 路径上。可能这就是您使用 Maven AspectJ 插件所做的,但如果是我这样做,我可能只会aop.xml
手动创建一个,使用@EnableLoadTimeWeaving
,然后丢弃该插件。您可能可以根据有效的方法来决定自己。
There can also be lifecycle issues if the aspect needs to intercept something that is used during the construction of the application context. You can maybe avoid that by not relying on any interception in @Bean
methods, or else you end up playing games with @DependsOn
to try and force a particular order of bean creation. Whether your app suffers from that yet I can't say.
如果方面需要拦截在构建应用程序上下文期间使用的某些内容,也可能存在生命周期问题。您可以通过不依赖@Bean
方法中的任何拦截来避免这种情况,否则您最终会玩游戏@DependsOn
以尝试强制创建特定的 bean 顺序。您的应用程序是否受到影响,但我不能说。
PREVIOUSLY (obsolete with Spring Boot 1.3):
以前(在 Spring Boot 1.3 中已过时):
Another stumbling block is that you are using Spring Boot and @EnableAutoConfiguration
which explicitly switches on @EnableAspectJAutoProxy
, and that switches off the AspectJ weaving for the Spring bean aspects. I actually have no idea if that is an intended side effect of @EnableAspectJAutoProxy
, but you can disable it by excluding it from the autoconfig, e.g.
另一个绊脚石是您正在使用 Spring Boot 并且@EnableAutoConfiguration
显式地打开@EnableAspectJAutoProxy
,并且关闭了 Spring bean 方面的 AspectJ 编织。我实际上不知道这是否是 的预期副作用@EnableAspectJAutoProxy
,但是您可以通过从自动配置中排除它来禁用它,例如
@ComponentScan
@EnableAutoConfiguration(exclude=AopAutoConfiguration.class)
public class Application {
...
}
N.B. you might not notice that weaving is switched off if you forget to exclude this config because Spring will create proxies for you and many of your aspects will just work anyway.
请注意,如果您忘记排除此配置,您可能不会注意到编织已关闭,因为 Spring 将为您创建代理,并且您的许多方面仍然可以正常工作。
回答by conanzhang
Here is my configuration:
这是我的配置:
@Component
@Aspect
public class WebControllerAop {
@Autowired
private PersonService personService;
//匹配com.zkn.learnspringboot.web.controller包及其子包下的所有类的所有方法
@Pointcut("execution(* com.zkn.learnspringboot.web.controller..*.*(..))")
public void executeService(){
}
}
@RestController
@EnableAutoConfiguration
@ComponentScan
public class FirstExample {
public static void main(String[] args) {
SpringApplication.run(FirstExample.class, args);
}
}
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
It can work well.
它可以很好地工作。