java 对 Spring 非托管 bean 的依赖注入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30890380/
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
Dependency Injection into Spring non-managed beans
提问by sparkyspider
I have a JPA domain class that is non managed. It is instantiated via the new
operator.
我有一个非托管的 JPA 域类。它是通过new
操作符实例化的。
UserAccount account = new UserAccount();
userRepository.save(account)
In my UserAccount
class, I have a beforeSave()
method which is dependent on my SecurityService
to hash encode a password.
在我的UserAccount
课堂上,我有一个beforeSave()
方法依赖于我SecurityService
对密码进行哈希编码。
My questions is "How do I get spring DI to inject the security service into my entity?". Seems that AspectJ and LoadTimeWeaving is what I need. I've tried an array for configurations, but I can't seem to get any of them to work. I always get a NullPointerException
when trying to call a method on the injected object.
我的问题是“如何让 spring DI 将安全服务注入到我的实体中?”。似乎 AspectJ 和 LoadTimeWeaving 是我需要的。我已经尝试了一个用于配置的数组,但我似乎无法让它们中的任何一个工作。NullPointerException
尝试在注入的对象上调用方法时,我总是得到一个。
UserAccount.java(This is the JPA Entity)
UserAccount.java(这是 JPA 实体)
@Entity
@Repository
@Configurable(autowire = Autowire.BY_TYPE)
public class UserAccount implements Serializable {
@Transient
@Autowired
SecurityService securityService;
private String passwordHash;
@Transient
private String password;
public UserAccount() {
super();
}
@PrePersist
public void beforeSave() {
if (password != null) {
// NullPointerException Here!!!
passwordHash = securityService.hashPassword(password);
}
}
}
Trying to indicate to spring to use AspectJ:
试图表明 spring 使用 AspectJ:
NitroApp.java(The main class)
NitroApp.java(主类)
@SpringBootApplication
@EnableTransactionManagement
@EnableSpringConfigured
@PropertySources(value = {@PropertySource("classpath:application.properties")})
public class NitroApp extends SpringBootServletInitializer {
public static void main (String[] args) {
SpringApplication.run(NitroApp.class);
}
}
build.gradle(Configuration)
build.gradle(配置)
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.2.RELEASE"
classpath "org.springframework:springloaded:1.2.2.RELEASE"
classpath "org.springframework:spring-aspects:4.1.6.RELEASE"
}
}
apply plugin: 'java'
apply plugin: 'aspectj'
apply plugin: 'application'
apply plugin: 'idea'
apply plugin: 'spring-boot'
repositories {
jcenter()
mavenLocal()
mavenCentral()
}
mainClassName = 'com.noxgroup.nitro.NitroApp'
applicationName = "Nitro"
idea {
module {
inheritOutputDirs = false
outputDir = file("$buildDir/classes/main/")
}
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("net.sourceforge.nekohtml:nekohtml:1.9.15")
compile("commons-codec:commons-codec:1.9")
compile("org.postgresql:postgresql:9.4-1201-jdbc41")
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
回答by Baptiste
You can inject Spring applicationContext in the class used to instanciate UserAccount.
您可以在用于实例化 UserAccount 的类中注入 Spring applicationContext。
@Autowired
private ApplicationContext applicationContext;
Then, create your UserAccount bean this way :
然后,以这种方式创建您的 UserAccount bean:
UserAccount userAccount = applicationContext.getBean(UserAccount.class);
This way, you can inject your required dependencies in the UserAccount class.
这样,您就可以在 UserAccount 类中注入所需的依赖项。
回答by ArunM
From your configuration, I am assuming that you are somehow expecting Spring to manage AOP for you. However since you are looking to @Autowired
on a non managed bean you will have to do the weaving yourself either through load time weaving or compile team weaving. Spring will only support method level aspects by default.
根据您的配置,我假设您以某种方式期望 Spring 为您管理 AOP。但是,由于您正在寻找@Autowired
非托管 bean,因此您必须通过加载时编织或编译团队编织自己进行编织。Spring 默认只支持方法级别的方面。
Because Load time weaving involves the use of javaagent as explained in 9.8.4(not always practical in a production scenario) I have gone ahead and used compile time weaving. Following code and config works for me.
因为加载时编织涉及使用 javaagent,如9.8.4 中所述(在生产场景中并不总是实用),所以我继续使用编译时编织。以下代码和配置对我有用。
Boot Config
启动配置
@SpringBootApplication
@EnableSpringConfigured
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
ApplicationContext ctx = SpringApplication.run(App.class, args);
Account account = new Account();
account.testConfigurable();
}
}
Account.java
账号.java
@Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true)
public class Account {
@Autowired
private SpringService service;
public void testConfigurable() {
System.out.println(service.returnHello());
}
}
SpringService.java
SpringService.java
@Service
public class SpringService {
public String returnHello() {
return "Hello";
}
}
Ugly pom.xml
丑陋的pom.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>1.8</source>
<target>1.8</target>
<Xlint>ignore</Xlint>
<complianceLevel>1.8</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>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.5</version>
</dependency>
</dependencies>
</plugin>
Following are the links I refered to.
以下是我参考的链接。
Since I am no expert on AOP, I am not sure of the knock on effect of configuring AOP the above way on ordinary aspect. A discussion here. If load time weaving is an option for you, you should go ahead and use this as discussed in the answer.
由于我不是AOP方面的专家,我不确定按照上述方式配置AOP对普通方面的影响。这里有一个讨论。如果加载时间编织是您的一个选项,您应该继续使用它,如答案中所述。