一、前言

本文承接上一节:Spring_总结_02_依赖注入

在上一节我们了解到依赖注入的实质就是装配。

这一节我们来学习下装配Bean的相关知识。

二、Bean的装配机制

1.三种装配机制

Spring提供了三种主要的bean的装配机制:

(1)注解配置——隐式的bean发现机制和自动装配

(2)Java配置——在Java中进行显示配置

(3)XML配置——在XML中进行显示配置

2.如何选择

(1)第一考虑自动装配,显示配置越少越好。

(2)当必须要显示配置的时候,再使用类型安全并且比XML更强大的JavaConfig

(3)最后,只有当你想用使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才应该使用XML。

这里以一个小例子来阐述组件扫描和装配。创建CompactDisc类,Spring会发现它并为其创建一个bean。然后,创建一个CDPlayer类,Spring会发现它,并将CompactDisc bean注入进来。

二、自动装配的过程

Spring从两个角度来实现自动化装配:

(1)组件扫描(component scanning):Spring 会自动发现应用上下文中所创建的bean

(2)自动装配(autowiring):Spring 自动满足bean之间的依赖

实现自动装配的过程如下:

(1)启用组件扫描: @ComponentScan

(2)声明bean      :  @Component

(3)  自动装配bean : @Autowired

三、启用组件扫描

组件扫描默认是不开启的,我们需要显示配置一下Spring,从而让它寻找带有@Component注解的类,并为其创建Bean。

配置类 CDPlayerConfig

@Configuration   //
@ComponentScan //
public class CDPlayerConfig {
}

1. 默认扫描包

1处:声明这是一个配置类

2处:开启组件扫描。默认会扫描配置类所在同级包及其子包,查找带有@Component注解的类。

2. 设置组件扫描的基础包

ComponentScan源码:

/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.context.annotation; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.type.filter.TypeFilter; /**
* Configures component scanning directives for use with @{@link Configuration} classes.
* Provides support parallel with Spring XML's {@code <context:component-scan>} element.
*
* <p>Either {@link #basePackageClasses} or {@link #basePackages} (or its alias
* {@link #value}) may be specified to define specific packages to scan. If specific
* packages are not defined, scanning will occur from the package of the
* class that declares this annotation.
*
* <p>Note that the {@code <context:component-scan>} element has an
* {@code annotation-config} attribute; however, this annotation does not. This is because
* in almost all cases when using {@code @ComponentScan}, default annotation config
* processing (e.g. processing {@code @Autowired} and friends) is assumed. Furthermore,
* when using {@link AnnotationConfigApplicationContext}, annotation config processors are
* always registered, meaning that any attempt to disable them at the
* {@code @ComponentScan} level would be ignored.
*
* <p>See {@link Configuration @Configuration}'s Javadoc for usage examples.
*
* @author Chris Beams
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.1
* @see Configuration
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan { /**
* Alias for {@link #basePackages}.
* <p>Allows for more concise annotation declarations if no other attributes
* are needed &mdash; for example, {@code @ComponentScan("org.my.pkg")}
* instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
*/
@AliasFor("basePackages")
String[] value() default {}; /**
* Base packages to scan for annotated components.
* <p>{@link #value} is an alias for (and mutually exclusive with) this
* attribute.
* <p>Use {@link #basePackageClasses} for a type-safe alternative to
* String-based package names.
*/
@AliasFor("value")
String[] basePackages() default {}; /**
* Type-safe alternative to {@link #basePackages} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {}; /**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
* <p>The default value of the {@link BeanNameGenerator} interface itself indicates
* that the scanner used to process this {@code @ComponentScan} annotation should
* use its inherited bean name generator, e.g. the default
* {@link AnnotationBeanNameGenerator} or any custom instance supplied to the
* application context at bootstrap time.
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; /**
* The {@link ScopeMetadataResolver} to be used for resolving the scope of detected components.
*/
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; /**
* Indicates whether proxies should be generated for detected components, which may be
* necessary when using scopes in a proxy-style fashion.
* <p>The default is defer to the default behavior of the component scanner used to
* execute the actual scan.
* <p>Note that setting this attribute overrides any value set for {@link #scopeResolver}.
* @see ClassPathBeanDefinitionScanner#setScopedProxyMode(ScopedProxyMode)
*/
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; /**
* Controls the class files eligible for component detection.
* <p>Consider use of {@link #includeFilters} and {@link #excludeFilters}
* for a more flexible approach.
*/
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN; /**
* Indicates whether automatic detection of classes annotated with {@code @Component}
* {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
*/
boolean useDefaultFilters() default true; /**
* Specifies which types are eligible for component scanning.
* <p>Further narrows the set of candidate components from everything in {@link #basePackages}
* to everything in the base packages that matches the given filter or filters.
* <p>Note that these filters will be applied in addition to the default filters, if specified.
* Any type under the specified base packages which matches a given filter will be included,
* even if it does not match the default filters (i.e. is not annotated with {@code @Component}).
* @see #resourcePattern()
* @see #useDefaultFilters()
*/
Filter[] includeFilters() default {}; /**
* Specifies which types are not eligible for component scanning.
* @see #resourcePattern
*/
Filter[] excludeFilters() default {}; /**
* Specify whether scanned beans should be registered for lazy initialization.
* <p>Default is {@code false}; switch this to {@code true} when desired.
* @since 4.1
*/
boolean lazyInit() default false; /**
* Declares the type filter to be used as an {@linkplain ComponentScan#includeFilters
* include filter} or {@linkplain ComponentScan#excludeFilters exclude filter}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter { /**
* The type of filter to use.
* <p>Default is {@link FilterType#ANNOTATION}.
* @see #classes
* @see #pattern
*/
FilterType type() default FilterType.ANNOTATION; /**
* Alias for {@link #classes}.
* @see #classes
*/
@AliasFor("classes")
Class<?>[] value() default {}; /**
* The class or classes to use as the filter.
* <p>The following table explains how the classes will be interpreted
* based on the configured value of the {@link #type} attribute.
* <table border="1">
* <tr><th>{@code FilterType}</th><th>Class Interpreted As</th></tr>
* <tr><td>{@link FilterType#ANNOTATION ANNOTATION}</td>
* <td>the annotation itself</td></tr>
* <tr><td>{@link FilterType#ASSIGNABLE_TYPE ASSIGNABLE_TYPE}</td>
* <td>the type that detected components should be assignable to</td></tr>
* <tr><td>{@link FilterType#CUSTOM CUSTOM}</td>
* <td>an implementation of {@link TypeFilter}</td></tr>
* </table>
* <p>When multiple classes are specified, <em>OR</em> logic is applied
* &mdash; for example, "include types annotated with {@code @Foo} OR {@code @Bar}".
* <p>Custom {@link TypeFilter TypeFilters} may optionally implement any of the
* following {@link org.springframework.beans.factory.Aware Aware} interfaces, and
* their respective methods will be called prior to {@link TypeFilter#match match}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
* </ul>
* <p>Specifying zero classes is permitted but will have no effect on component
* scanning.
* @since 4.2
* @see #value
* @see #type
*/
@AliasFor("value")
Class<?>[] classes() default {}; /**
* The pattern (or patterns) to use for the filter, as an alternative
* to specifying a Class {@link #value}.
* <p>If {@link #type} is set to {@link FilterType#ASPECTJ ASPECTJ},
* this is an AspectJ type pattern expression. If {@link #type} is
* set to {@link FilterType#REGEX REGEX}, this is a regex pattern
* for the fully-qualified class names to match.
* @see #type
* @see #classes
*/
String[] pattern() default {}; } }

其中,通过 basePackages 可用String类型来指定基础包。

通过 basePackageClasses 可用类或接口(建议使用空标记接口)来指定基础包,这些类或接口所在的包将会作为组件扫描的基础包。

示例如下:

@Configuration
@ComponentScan(basePackages = "com.ray.soundsystem")
public class CDPlayerConfig {
} @Configuration
@ComponentScan(basePackages = {"com.ray.soundsystem","com.ray.video"})
public class CDPlayerConfig {
}
public interface SoundSystemScanConfig {

}

public interface VideoScanConfig {

}

@Configuration
@ComponentScan(basePackageClasses = {SoundSystemScanConfig.class,VideoScanConfig.class})
public class CDPlayerConfig {
}

四、声明bean

1.  @Component声明bean

@Component
public class ComPactDisc { public void play(){
System.out.println("play music");
}
}

如上述代码所示,通过@Component来声明一个组件,表明该类会作为组件类,并告知Spring要为这个类创建bean。

可用以下注解来声明一个组件:

  • @Component  : 标注通用组件
  • @Controller     : 标注控制器
  • @Service        :  标注Service
  • @Respository :  标注数据访问层

通过查看源码,可知,@Controller、@Service、@Repository 能声明bean 是因为他们都组合了@Component。

以Controller为例:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller

2.为组件命名

Spring 会为所有的bean都指定一个ID,默认为类名首字母小写。

但也可通过@Component的value属性来将为bean命名,如:

@Component("compactDisc1")
public class ComPactDisc { public void play(){
System.out.println("play music");
}
}

五、自动装配bean

public class CDPlayer {

    private ComPactDisc cd;

    @Autowired
public CDPlayer( ComPactDisc cd){
this.cd =cd;
} public void play(){
cd.play();
}
}

(1)通过 @Autowired 注解,声明让Spring来自动注入符合要求的bean

(2)@Autowired 注解默认按类型匹配,可用在属性上以及任何方法上。

(3)当@Autowired 注解用在方法上时,Spring会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配依赖需求,那么这个bean将会被装配进来。

在Spring中,只要容器中存在某个bean,就可以在另外一个Bean的声明方法的参数中注入。

用来注入bean的注解还有:

@Inject

@Resource

最新文章

  1. 以实际的WebGIS例子探讨Nginx的简单配置
  2. ORACLE VARCHAR2最大长度问题
  3. servlet到底是什么?
  4. BZOJ4525——[Usaco2016 Jan]Angry Cows
  5. nav ccsss
  6. hdu 2090
  7. PLSQL_基础系列06_判断操作NVL / NULLIF / COALESCE / NVL2(案例)
  8. Oracle 查看表空间大小及其扩展
  9. Python+PyQt 数据库基本操作
  10. Web页面布局方式小结
  11. Spring管理Hibernate
  12. 更加 &quot;深入&quot; 理解多态
  13. 教你如何实现微信小程序与.net core应用服务端的无状态身份验证
  14. 一个App与另一个App之间的交互,添加了自己的一些理解
  15. 原生JS插件(超详细)
  16. 646. Maximum Length of Pair Chain(medium)
  17. Linux的vim编辑器中的翻页命令
  18. Caffeine缓存
  19. Linux中进程与线程的概念以及区别
  20. iOS 证书申请新步骤

热门文章

  1. android 支付宝集成 使用常见错误
  2. HTMLbutton控件中文字显示一直不居中
  3. Django:popup弹出框简单应用实例
  4. PAT 天梯赛 L1-027. 出租 【模拟】
  5. CSR1010 sdk蓝牙
  6. HTTP协议—常见的HTTP响应状态码解析
  7. P3794 签到题IV
  8. async/await方法解析
  9. PreTranslateMessage作用和使用方法
  10. mongodb的原子性(Atomicity)和事物 (Transactions)