Spring_总结_03_装配Bean(一)之自动装配

一、前言

本文承接上一节: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   //1
@ComponentScan   //2
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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

weblogic 10.x 上开发restful服务

之前已经学习过 利用JAX-RS快速开发RESTful 服务,当时是jboss环境,如果原封不动的迁移到weblogic 10.x 版本,会杯具的发现应用启动失...

21810
来自专栏菩提树下的杨过

需要安全认证的远程EJB调用示例(Jboss EAP 6.2环境)

一,Remote EJB 服务接口定义: 1 package yjmyzz.ejb.server.helloworld; 2 3 public interfa...

2405
来自专栏菩提树下的杨过

mac:在当前文件夹打开terminal终端

System Preferences -> Keyboard -> Shortcuts -> Services -> New Terminal at Folde...

2258
来自专栏A周立SpringCloud

使用Feign实现Form表单提交

之前,笔者写了《使用Spring Cloud Feign上传文件》。近日,有同事在对接遗留的Struts古董系统,需要使用Feign实现Form表单提交。其实步...

5036
来自专栏Java后端技术

SpringBoot初体验及原理解析

​  上篇文章,我们聊到了SpringBoot得以实现的幕后推手,这次我们来用SpringBoot开始HelloWorld之旅。SpringBoot是Sprin...

1422
来自专栏ImportSource

Spring5以来注册Bean的各种姿势,特别最后的纯编码注册值得尝试

各位好,今天我们的内容是有关Spring 5以来有关注册bean的几种方式。前面两三个是比较常用的方式,最后两种是只有在特殊的场合下才会被用到和想到。我们会分别...

1.3K7
来自专栏好好学java的技术栈

SpringMVC+RestFul详细示例实战教程(实现跨域访问)

**REST(Representational State Transfer)**,中文翻译叫“表述性状态转移”。是 Roy Thomas Fielding 在...

2044
来自专栏Netkiller

怎样制作RPM包

怎样制作RPM包 摘要 我在网上找RPM包的制作例子几乎都是C源码编译安装然后生成RPM包, 而我的程序不是C写的很多时候是脚本语言如Python, PHP 甚...

6346
来自专栏刘君君

一个feign使用不当的问题

以上配置在不熟悉feign-hystrix 或者查看 Feign Hystrix Fallbacks 的可能感觉并没有问题,项目启动也是正常

1433
来自专栏技术总结

献给移动端的服务器搭建

application.properties这个是项目的一些配置,举例一下默认是8080端口,我们如果想改下端口的话,就可以在配置增加

2202

扫码关注云+社区

领取腾讯云代金券