- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我有一个原型(prototype)范围的bean,我想通过@Autowired 注解注入(inject)它。在这个 bean 中,还有 @PostConstruct 方法,它没有被 Spring 调用,我不明白为什么。
我的 bean 定义:
package somepackage;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Scope("prototype")
public class SomeBean {
public SomeBean(String arg) {
System.out.println("Constructor called, arg: " + arg);
}
@PostConstruct
private void init() {
System.out.println("Post construct called");
}
}
我要注入(inject) bean 的 JUnit 类:
package somepackage;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath*:applicationContext-test.xml")
public class SomeBeanTest {
@Autowired
ApplicationContext ctx;
@Autowired
@Value("1")
private SomeBean someBean;
private SomeBean someBean2;
@Before
public void setUp() throws Exception {
someBean2 = ctx.getBean(SomeBean.class, "2");
}
@Test
public void test() {
System.out.println("test");
}
}
Spring 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="somepackage"/>
</beans>
执行的输出:
Constructor called, arg: 1
Constructor called, arg: 2
Post construct called
test
当我通过从 ApplicationContext
调用 getBean
来初始化 bean 时,一切都按预期工作。我的问题是为什么通过 @Autowire
和 @Value
组合注入(inject) bean 不调用 @PostConstruct
方法
最佳答案
为什么使用@Value 而不是@Autowired?
@Value
注释用于注入(inject)值,通常作为目标字符串、原语、装箱类型和 java 集合。
The @Value annotation can be placed on fields, methods and method/constructor parameters to specify a default value.
Value
接收一个字符串表达式,spring 使用它来处理到目标对象的转换。这种转换可以通过Spring's type conversion , java bean property editor ,以及 Spring's SpEL expresions .原则上,这种转换的结果对象不由 spring 管理(即使您可以从任何这种方法返回一个已经管理的 bean)。
另一方面,AutowiredAnnotationBeanPostProcessor是一个
BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary config methods. Such members to be injected are detected through a Java 5 annotation: by default, Spring's @Autowired and @Value annotations.
该类处理字段注入(inject),解析依赖,最终调用方法doResolveDependency , 是在解决注入(inject)的“优先级”的这个方法中,springs 检查是否存在通常是表达式字符串的建议值,这个建议值是注释 Value
的内容,所以如果存在,则调用类 SimpleTypeConverter已完成,否则 spring 会寻找候选 bean 并解析 Autowiring 。
@Autowired
被忽略而使用@Value
的原因仅仅是因为首先检查了 value 的注入(inject)策略。显然总是要优先考虑,当使用多个冲突的注解时,spring 也可能会抛出异常,但在这种情况下,是由先前对 sugested 值的检查确定的。
我找不到任何与这个“优先级”相关的东西是 spring,但简单是因为不打算一起使用这个注解,就像它不打算使用 @Autowired
和 @Resource
一起。
@Value 为什么会创建对象的新实例
前面说过类SimpleTypeConverter
是在建议值出现的时候调用的,具体调用的是方法convertIfNecessary ,这是执行将字符串转换为目标对象的方法,同样可以使用属性编辑器或自定义转换器来完成,但这里没有使用这些。也不使用 SpEL 表达式,仅使用字符串文字。
Spring首先检查目标对象是字符串还是集合/数组(可以转换例如逗号分隔的列表),然后检查目标是否是枚举,如果是,它会尝试转换字符串,如果是不是,不是接口(interface)而是类,它检查 Constructor(String)
的存在以最终创建对象(不由 spring 管理)。基本上,这个转换器尝试了许多不同的方法来将字符串转换为最终的对象。
此实例化只能使用字符串作为参数,例如,如果您使用 SpEL 表达式来返回长 @Value("#{2L}")
,并使用带有一个 Constructor(Long)
它将抛出一个带有类似消息的 IllegalStateException
:
Cannot convert value of type 'java.lang.Long' to required type 'com.fiberg.test.springboot.object.Hut': no matching editors or conversion strategy found
可能的解决方案
使用简单的@Configuration 类作为供应商。
public class MyBean {
public MyBean(String myArg) { /* ... */ }
// ...
@PostConstruct public init() { /* ... */ }
}
@Configuration
public class MyBeanSupplier {
@Lazy
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
proxyMode = ScopedProxyMode.NO)
public MyBean getMyBean(String myArg) {
return new MyBean(myArg);
}
}
您可以将 MyBean 定义为 MyBeanSupplier 类中的静态类,如果它是唯一的方法。此外,您不能使用代理模式 ScopedProxyMode.TARGET_CLASS,因为您需要将参数作为 bean 提供,而传递给 getMyBean
的参数将被忽略。
使用这种方法,您将无法 Autowiring bean 本身,而是 Autowiring 供应商,然后调用 get 方法。
// ...
public class SomeBeanTest {
@Autowired private MyBeanSupplier supplier;
// ...
public void setUp() throws Exception {
someBean = supplier.getMyBean("2");
}
}
您还可以使用应用程序上下文创建 bean。
someBean = ctx.getBean(SomeBean.class, "2");
而且@PostConstruct
方法不管你用哪一个都应该被调用,但是@PreDestroy
is not called in prototype beans .
关于java - 为什么使用构造函数参数 Autowiring 原型(prototype)bean时不调用@PostConstruct方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49007559/
好吧,我怀疑这是一个独特的情况,所以要么有人这样做了,要么有人认为这是不可能的,至少以我所要求的方式。 我有 2 个原型(prototype)变量(函数),一个是父变量,另一个是助手。我想做的是从助手
这是 JavaScript 大师的问题。我正在尝试更优雅地使用 JavaScript 原型(prototype)模型。这是我的实用程序代码(它提供了真实的原型(prototype)链并正确使用 ins
我们知道在 JavaScript 中有一个用于数组的 .forEach() 方法。但是字符串没有内置该方法。 那么,下面的代码片段有没有问题:String.prototype.forEach = Ar
我们知道在 JavaScript 中有一个用于数组的 .forEach() 方法。但是字符串没有内置该方法。 那么,下面的代码片段有没有问题:String.prototype.forEach = Ar
我看到了两种不同的模式和解释。来自 DailyJS 和许多其他人的一篇:矩形.prototype = new Shape(); 然后是 Crockford 的 here 这意味着只是 矩形.proto
尝试在 Object.prototype 以及 String.prototype 和 Number.prototype 上定义一个 hashCode 方法>。我正在使用以下方法定义原型(prototy
在本教程中,您将借助示例了解 JavaScript 中的原型。 在学习原型之前,请务必查看以下教程: JavaScript 对象 JavaScript 构造函数 如您所知,您可以使用对象构造函
当构造新对象时,该对象被设置为委托(delegate)任何尚未显式设置为其构造函数原型(prototype)的属性。这意味着我们可以稍后更改原型(prototype),并且仍然可以看到实例中的更改。
我正在努力获得更好的 JavaScript 实用知识。所以,我买了 Douglas Crockford 的书“JavaScript the good parts”。 我现在很难掌握原型(prototy
我的理解是相同类型的所有对象将共享相同的原型(prototype)。因此对原型(prototype)的更改将反射(reflect)在每个对象上。但是值类型的属性似乎不是这样。这种属性是如何存储的? f
这个问题在这里已经有了答案: 关闭 12 年前。 Possible Duplicate: JavaScript: Class.method vs. Class.prototype.method 创建
为什么在 MDN 函数中 polyfills 使用“if (!Array.prototype.filter)”? if (!Array.prototype.filter) { Array.prot
这个问题已经有答案了: Assigning prototype methods *inside* the constructor function - why not? (6 个回答) 已关闭 7 年
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 9 年前。 Improve this qu
面向对象有一个特征是继承,即重用某个已有类的代码,在其基础上建立新的类,而无需重新编写对应的属性和方法,继承之后拿来即用; 。 在其他的面向对象编程语言比如Java中,通常是指,子类继承父类的属性和
OOP 中原型(prototype)设计模式最重要的部分之一是我们不会从头开始创建新对象,我们只是使用 clone() 函数从现有对象克隆它们。 那么clone()函数是深拷贝还是浅拷贝? 如果它是一
在进行原型(prototype)设计时,您在多大程度上放弃了最佳实践来支持代码和修复黑客攻击?当然,代码并不打算在完整的生产环境中保留。 补充:我正在研究一个用 Python 制作的相当大的半工作原型
我开始学习设计模式。我知道原型(prototype)是用来制作我已经拥有的对象的精确副本,而享元是用来制作类似的对象。 我已经编写了 2D 平台游戏,例如马里奥(Java)。有很多相同的敌人,唯一的区
我正在使用 Maven 生成原型(prototype)。我能够使原型(prototype)生成正常,并且它生成的项目模板按预期工作。唯一的问题是在我的 shell 脚本中。脚本中注释掉的任何内容都会被
我想用 primefaces 配置一个 Java EE 项目。我在某处读到可以使用 mvn arechetype:generate 创建项目结构。当我使用它时,我只看到了 41 个选项,而在该教程中,
我是一名优秀的程序员,十分优秀!