了解Spring @Autowired的用法
我正在阅读春季网站,了解Spring Autowired注释:
3.9.2 @Autowired和@Inject
我无法理解下面的例子。 我们是否需要在XML中做一些工作?
例1
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
例2
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
这两个类如何自动实现相同的接口并使用相同的类?
例:
class Red implements Color class Blue implements Color class myMainClass{ @Autowired private Color color; draw(){ color.design(); } }
哪种devise方法会被调用? 我如何确保Red类的devise方法被调用而不是Blue?
@Autowired
注释允许你跳过configuration的其他地方,只是为你做。 假设你的包是com.mycompany.movies
你必须把这个标签放在你的XML(application context file)中:
<context:component-scan base-package="com.mycompany.movies" />
这个标签会做一个自动扫描。 假设每个必须成为bean的类都使用@Component
(对于简单bean)或@Controller
(对于servlet控件)或@Repository
(对于DAO
类)进行注释,而这些类位于com.mycompany.movies
,Spring会find所有这些,并为每个bean创build一个bean。 这是在两个类的扫描中完成的 – 第一次它只search需要成为一个bean的类并映射它需要做的注入,在第二次扫描时注入bean。 当然,您可以在更传统的XML文件或@Configuration类(或这三者的任意组合)中定义bean。
@Autowired
注释告诉Spring注入需要发生的地方。 如果你把它放在setMovieFinder
方法setMovieFinder
它可以理解(通过前缀set
+ @Autowired
注解)一个bean需要被注入。 在第二个扫描中,Springsearch一个types为MovieFinder
的bean,如果它find了这个bean,它将它注入到这个方法中。 如果发现两个这样的bean,你将会得到一个Exception
。 为了避免这个Exception
,你可以使用@Qualifier
注解,并通过下面的方式告诉它注入两个bean中的哪一个:
@Qualifier("redBean") class Red implements Color { // Class code here } @Qualifier("blueBean") class Blue implements Color { // Class code here }
或者,如果您更愿意在XML中声明这些bean,它将看起来像这样:
<bean id="redBean" class="com.mycompany.movies.Red"/> <bean id="blueBean" class="com.mycompany.movies.Blue"/>
在@Autowired
声明中,您还需要添加@Qualifier
来分辨要注入的两个颜色bean中的哪一个:
@Autowired @Qualifier("redBean") public void setColor(Color color) { this.color = color; }
如果你不想使用两个注解( @Autowired
和@Qualifier
),你可以使用@Resource
来组合这两个:
@Resource(name="redBean") public void setColor(Color color) { this.color = color; }
@Resource
(你可以在这个答案的第一个注释中读到一些关于它的额外的数据)让你使用两个注释,而只使用一个。
我只会再添加两条评论:
- 好的做法是使用
@Inject
而不是@Autowired
因为它不是Spring特定的,并且是JSR-330
标准的一部分 。 - 另一个好的做法是将
@Inject
/@Autowired
放在构造函数中而不是方法上。 如果将它放在构造函数中,则可以validation注入的Bean是否为空,并且在尝试启动应用程序时会快速失败,并且在需要实际使用Bean时避免NullPointerException
。
所以,总结一下: @Autowired
注解不需要你自己在XML文件中(或者其他任何方式)进行布线,只需要find需要注入的地方,并且为你做。
更新 :为了完成这个图片,我创build了一个关于@Configuration
类的新问题 。
示例中没有任何内容说“实现相同接口的类”。 MovieCatalog
是一个types, CustomerPreferenceDao
是另一个types。 spring可以很容易地把它们分开。
在Spring 2.x中,bean的连线主要是通过bean的ID或名字发生的。 Spring 3.x仍然支持这个function,但通常情况下,您将拥有一个具有特定types的bean的实例 – 大多数服务都是单例。 为这些人创build名字是很乏味的。 所以Spring开始支持“autowire type”。
这些示例显示的是可以使用各种方法将bean注入字段,方法和构造函数。
XML已经包含了Spring需要的所有信息,因为您必须在每个bean中指定完全限定的类名称。 但是,您需要小心接口,但是:
这种自动assembly将失败:
@Autowired public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }
由于Java不保存字节码中的参数名称,因此Spring无法区分这两个bean。 修正是使用@Qualifier
:
@Autowired public void prepare( @Qualifier("bean1") Interface1 bean1, @Qualifier("bean2") Interface1 bean2 ) { ... }
是的,您可以configurationSpring servlet上下文xml文件来定义您的bean(即类),以便它可以为您自动注入。 然而,请注意,你必须做其他的configuration才能使Spring运行起来,而最好的方法是按照教程进行操作。
一旦你的Springconfiguration好了,你可以在Spring servlet上下文xml文件中为上面的例子1做下面的工作(请把 com.movies的包名replace成真正的包名,如果这是第三方类,然后确保相应的jar文件在类path中):
<beans:bean id="movieFinder" class="com.movies.MovieFinder" />
或者如果MovieFinder类有一个具有原始值的构造函数,那么你可以这样,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" > <beans:constructor-arg value="100" /> </beans:bean>
或者如果MovieFinder类有一个构造函数期望另一个类,那么你可以做这样的事情,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" > <beans:constructor-arg ref="otherBeanRef" /> </beans:bean>
…其中' otherBeanRef '是另一个有预期类的引用的bean。
@Autowired
让Spring使用@Autowired注释将其他bean自动连线到您的类中。
@Service public class CompanyServiceImpl implements CompanyService { @Autowired private CompanyDAO companyDAO; ... }
Spring Annotation提示Spring bean可以按名称或types进行连接。 @Autowire默认是一个types驱动注入。 可以使用@Qualifier spring注释来进一步微调自动assembly。 @Resource(javax.annotation.Resource)注释可以用于按名称连线。 本身被定义为集合或映射types的Bean不能通过@Autowired注入,因为types匹配不适用于它们。 对这样的bean使用@Resource,通过唯一名称引用特定的集合或映射bean