zoukankan      html  css  js  c++  java
  • 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 {};
    
        }
    
    }
    View Code

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

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

    示例如下:

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

    四、声明bean

    1.  @Component声明bean

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

    如上述代码所示,通过@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");
        }
    }
    View Code

    五、自动装配bean

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

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

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

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

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

     用来注入bean的注解还有:

    @Inject 

    @Resource

  • 相关阅读:
    Jupyter notebook中的Cell and Line Magics
    numpy中array数组对象的储存方式(n,1)和(n,)的区别
    机器学习中的标准化方法(Normalization Methods)
    matplotlib添加子图(拼图功能)
    matplotlib.pyplot.plot详解
    一行代码让你的python运行速度提高100倍
    一个简单的Shell脚本(解决windows上文本在macos上乱码问题)
    解决Mac上打开txt文件乱码问题
    LaTeX中常用代码段snippets(持续更新)
    LaTeX实时预览中文
  • 原文地址:https://www.cnblogs.com/shirui/p/9379975.html
Copyright © 2011-2022 走看看