澳门新葡亰平台官网摘录一些Spring文档的内容(二)

澳门新葡亰平台官网 3

Spring对于Bean的注重性注入,帮忙多样批注情势:

1、@Inject

依赖注释的容器配置

通过依据注明的配置提供了XML设置的代替情势,该配置正视于元数据(metadata)来三番三回组件。

@Resource
javax.annotation
JSR250 (Common Annotations for Java)

@Inject
javax.inject
JSR330 (Dependency Injection for Java)

@Autowired
org.springframework.bean.factory
Spring
  • javax.inject
  • JSR330 (Dependency Injection for Java)

注解

<context:annotation-config/>
只会在平等应用上下文搜索bean定义,所以,在WebApplicationContext中应用<context:annotation-config/>,它只会检查在Controller层标志@Autowired表明的bean而不会到你的瑟维斯层中去找(由此Controller和Service都要分别定义<context:annotation-config/>)
注意:<context:annotation-config/>和<context:component-scan>的区别

  • @Required
    被标记的bean必得的相关值必需被填充(注入State of Qatar,
    若无被填充(注入),则容器会报错。那允许热切和分明的退步,今后制止NullPointerExceptions等

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

注意
一经您用java config方式布署bean的话@Required是不起功用的
(https://stackoverflow.com/questions/16769360/how-does-required-annotation-work-with-javaconfig)

So, to summarize: @Required
doesn’t work with @Configuration
classes by default. If you need to make sure that all your properties
are set, you can just as well do it yourself when you create the bean
in the @Bean
methods (By calling some init
method that performs such validations, or just supplying the required
properties yourself). And if you really need to make the @Required
annotation work, you’d need to use your own implementation of the
RequiredAnnotationBeanPostProcessor ,
register it as a bean in the spring context and give up the benefits
of context:annotation-config
.

  • @Autowired
    能够注脚在setter方法上,布局器上,拥有自由名称和/或多个参数的方法,字段上(田野先生s),数组类型的字段或艺术,集结类型的字段或方式上

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...

}

注意
Map类型供给key为String类型才具被注入,key值会对应bean名称。容器会将相符项指标bean都注入到map中,当中key值正是相应的bean名称。

  • @Primary
    @Autowired是依据项目自动装配的(@Resource(这么些注脚归属J2EE的),暗中同意安装名称举行装配),遵照项目标自行装配或然会促成多个候选,因而普通要对接受经过由更加的多的调整,此中一个主意时接纳Spring的@Primary表明。当有七个附后必要的候选bean时,标有primary的Bean会被注入

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...

}
  • @Qualifier
    依据类别的全自动装配大概会形成几个候选,由此普通要对接纳进程由越来越多的主宰,Spring的@Qualifier注释,能够将范围符值与一定参数关联,缩短类型相配集

public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...

}

@Qualifier也能够标明在单独的布局器参数或艺术参数上。

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

<?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:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

限制符也适用于类型化的会集,如上所述,譬喻Set<MovieCatalog>。在此种地方下,依据申明的限制符的具有匹配的bean将作为会集实行注入。那象征约束词不自然是独一的;
它们只是构成过滤标准。举例,您能够MovieCatalog使用相通的界定符值“action”
定义多个bean,全数这一个bean都将注入到Set<MovieCatalog>注释中@Qualifier(“action”卡塔尔(قطر‎。

注意
设若你思忖按名称注入Bean,不要用@Autowired,请使用@Resource(JS途锐-250定义的)

  • @Resource
    @Resource暗中同意按名称注入,若无生硬钦点名称,则暗中同意名称来自字段名称或setter方法。在一个字段的状态下,它要求字段名称;
    在setter方法的意况下,它将应用bean属性名称。若无分明钦定名称,默许名称也找不到对应的bean就和@Autowired近似.

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

如上多少个注明,小编都做了相应的演习去印证https://github.com/wingofthestar/SpringLearn

位于site.yourdiary.anno目录下

澳门新葡亰平台官网 1

目录.png


澳门新葡亰平台官网 ,@Controller、@Service、@Repository、@Component
@Component是注脚着其余被Spring管理的构件(Bean)
@Repository, @Service,
@Controller是对于@Component更具体的一定用例的构件。

你可以用
@Component表明组件类,但要是用@Repository,@Service或许@Controller
,你的类有十分大希望能越来越好地被工具管理,或与切面举行关联。

  • 元注解
    Spring
    提供的无数解说能够在你和煦的代码中用作元阐明。元注明是足以选择于另三个疏解的注释。举例,@Service注明正是以@Component为元证明的

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring will see this and treat @Service in the same way as @Component
public @interface Service {

    // ....
}

元注明能够组合成组合注脚,就举例在SpringMVC中@RestController就是由@Controller和@ResponseBody组合而成的。

  • 自动物检疫查测量检验类和登记bean定义
    Spring能够自动物检疫查评定评释有(stereotyped)的类,并在ApplicationContext中登记相应的BeanDeinitions.
    例如:

@Service
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

@Repository
public class JpaMovieFinder implements MovieFinder {
    // implementation elided for clarity
}

为了自动物检疫查测验那个类,并且注册相应的Bean,你须要增多在@Configuration类上标明@ComponentScan,并且标识basePackages属性为那四个类的父包。(也足以用逗号、分号、空格分隔的列出各样class的父包)。

java config写法

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}

xml写法

<?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="org.example"/>

</beans>

注意
<context:component-scan>启用(包括卡塔尔了<context:annotation-config>的意义,所以选择了<context:component-scan>就没有必要再增多<context:component-scan>

Furthermore, the AutowiredAnnotationBeanPostProcessor and
CommonAnnotationBeanPostProcessor are both included implicitly when
you use the component-scan element. That means that the two components
are autodetected and wired together – all without any bean
configuration metadata provided in XML.

AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也同临时候被自动检查实验到并登记

直观上看起来,@Autowired是Spring提供的笺注,别的多少个都以JDK自身内建的注释,Spring对那几个注脚也扩充了支撑。可是选用起来那三者到底有如何区别吗?我通过艺术的测验,发掘一些风趣的风味。

那是JSCR-V330中的标准,通过AutowiredAnnotationBeanPostProcessor类达成的信赖注入。

利用过滤器自定义扫描(路线卡塔尔

澳门新葡亰平台官网 2

过滤器类型.png

上面包车型大巴例子展示了configuration忽视了具有@Repository表明,并用”stub”
respositories

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>

分别计算如下:

一、@Autowired有个required属性,能够布署为false,这种景况下如果未有找到呼应的bean是不会抛非常的。@Inject和@Resource未有提供对应的计划,所以必得找到不然会抛格外。

二、
@Autowired和@Inject基本是相似的,因为两方都是运用AutowiredAnnotationBeanPostProcessor来拍卖重视注入。可是@Resource是个不等,它应用的是CommonAnnotationBeanPostProcessor来拍卖信赖注入。当然,两个都以BeanPostProcessor。

@Autowired和@Inject
- 默认 autowired by type
- 可以 通过@Qualifier 显式指定 autowired by qualifier name。
- 如果 autowired by type 失败(找不到或者找到多个实现),则退化为autowired by field name

@Resource
- 默认 autowired by field name
- 如果 autowired by field name失败,会退化为 autowired by type
- 可以 通过@Qualifier 显式指定 autowired by qualifier name
- 如果 autowired by qualifier name失败,会退化为 autowired by field name。但是这时候如果 autowired by field name失败,就不会再退化为autowired by type了。

TIPS Qualified name VS Bean name

在Spring设计中,Qualified name并不相仿Bean
name,前者必得是当世无双的,可是前边三个相同于tag大概group的效率,对一定的bean举办归类。可以达成getByTag(groupState of Qatar的职能。对于XML配置的bean,能够经过id属性钦命bean
name(若无一点点名,私下认可使用类名首字母小写),通过标签内定qualifier
name:

<bean id="lamborghini" class="me.arganzheng.study.spring.autowired.Lamborghini">
    <qualifier value="luxury"/>
    <!-- inject any dependencies required by this bean -->
</bean>

假定是通过申明方式,那么能够通过@Qualifier注脚钦点qualifier
name,通过@Named恐怕@Component(@Service,@Repository等)的value值钦赐bean
name:

@Component("lamborghini")
@Qualifier("luxury")
public class Lamborghini implements Car {

}

或者

@Component
@Named("lamborghini")
@Qualifier("luxury")
public class Lamborghini implements Car {

}

一律,若无一点名bean
name,那么Spring会暗中认可是用类名首字母小写(Lamborghini=>lamborghini卡塔尔。

三、
通过Anotation注入信任的方法在XML注入情势早先开展。如若对同三个bean的依赖相同的时候利用了二种注入格局,那么XML的优先。可是差异担补肾益气过Anotation注入的依附没办法注入XML中安顿的bean,正视注入是在bean的登记之后进展的。

四、近来的autowired by
type情势(笔者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor达成都是有”bug”的,也等于说@Autowired和@Inject都以有坑的(称之为坑,不称之为bug是因为相仿是多此一举的。。)。那是来源于线上的多个bug,也是这边文章的写作原因。现场如下:

application-context.xml中犹如下概念:

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

    <context:annotation-config />

    <context:component-scan base-package="me.arganzheng.study" />

    <util:constant id="en"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN" />
    <util:constant id="ja"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.JP" />
    <util:constant id="ind"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.IND" />
    <util:constant id="pt"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.PT" />
    <util:constant id="th"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.TH" />
    <util:constant id="ar"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.AR" />
    <util:constant id="en-rIn"
        static-field="me.arganzheng.study.spring.autowired.Constants.Language.EN_RIN" />

    <util:map id="languageChangesMap" key-type="java.lang.String"
        value-type="java.lang.String">
        <entry key="pt" value="pt" />
        <entry key="br" value="pt" />
        <entry key="jp" value="ja" />
        <entry key="ja" value="ja" />
        <entry key="ind" value="ind" />
        <entry key="id" value="ind" />
        <entry key="en-rin" value="en-rIn" />
        <entry key="in" value="en-rIn" />
        <entry key="en" value="en" />
        <entry key="gb" value="en" />
        <entry key="th" value="th" />
        <entry key="ar" value="ar" />
        <entry key="eg" value="ar" />
    </util:map>

</beans>

其间static-田野同志应用的常量定义在如下类中:

package me.arganzheng.study.spring.autowired;

public interface Constants {

    public interface Language {
        public static final String EN = "CommonConstants.LANG_ENGLISH";
        public static final String JP = "CommonConstants.LANG_JAPANESE";
        public static final String IND = "CommonConstants.LANG_INDONESIAN";
        public static final String PT = "CommonConstants.LANG_PORTUGUESE";
        public static final String TH = "CommonConstants.LANG_THAI";
        public static final String EN_RIN = "CommonConstants.LANG_ENGLISH_INDIA";
        public static final String AR = "CommonConstants.LANG_Arabic";
    }
}

下一场一旦我们在代码中如下宣示重视:

public class AutowiredTest extends BaseSpringTestCase {

    @Autowired
    private Map<String, String> languageChangesMap;

    @Test
    public void testAutowired() {
        notNull(languageChangesMap);
        System.out.println(languageChangesMap.getClass().getSimpleName());
        System.out.println(languageChangesMap);
    }
}

Guess what,离奇的作业产生了!

运作结果如下:

LinkedHashMap
{en=CommonConstants.LANG_ENGLISH, ja=CommonConstants.LANG_JAPANESE, ind=CommonConstants.LANG_INDONESIAN, pt=CommonConstants.LANG_PORTUGUESE, th=CommonConstants.LANG_THAI, ar=CommonConstants.LANG_Arabic, en-rIn=CommonConstants.LANG_ENGLISH_INDIA}

也正是说Map

严重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@5c51ee0a] to prepare test instance [me.arganzheng.study.spring.autowired.AutowiredTest@6e301e0]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'me.arganzheng.study.spring.autowired.AutowiredTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Map me.arganzheng.study.spring.autowired.AutowiredTest.languageChangesMap; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    ...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 28 more

debug了一下,开掘真就是Spring的二个bug。在DefaultListableBeanFactory的那一个主意出标题了:

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
        ...     

        else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> keyType = descriptor.getMapKeyType();
            if (keyType == null || !String.class.isAssignableFrom(keyType)) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
                            "] must be assignable to [java.lang.String]");
                }
                return null;
            }
            Class<?> valueType = descriptor.getMapValueType();
            if (valueType == null) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
                }
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            return matchingBeans;
        }
        ...
    }

重大在这里一句:Map

严重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@9476189] to prepare test instance [me.arganzheng.study.spring.autowired.AutowiredTest@2d546e21]
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=languageChangesMap)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 28 more

debug了一下,开掘跟未有一点名qualifie name是一律的实行路径。不是内定了bean
name了呢?为啥依然autowired by
type呢?留心查阅了弹指间才开掘。DefaultListableBeanFactory的doResolveDependency方法对第一对品种做了分别:

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return (descriptor.getField() != null ?
                    converter.convertIfNecessary(value, type, descriptor.getField()) :
                    converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
        }

        if (type.isArray()) {
            Class<?> componentType = type.getComponentType();
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return converter.convertIfNecessary(matchingBeans.values(), type);
        }
        else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> elementType = descriptor.getCollectionType();
            if (elementType == null) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
                }
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return converter.convertIfNecessary(matchingBeans.values(), type);
        }
        else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> keyType = descriptor.getMapKeyType();
            if (keyType == null || !String.class.isAssignableFrom(keyType)) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
                            "] must be assignable to [java.lang.String]");
                }
                return null;
            }
            Class<?> valueType = descriptor.getMapValueType();
            if (valueType == null) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
                }
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
                }
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            return matchingBeans;
        }
        else {
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                if (descriptor.isRequired()) {
                    raiseNoSuchBeanDefinitionException(type, "", descriptor);
                }
                return null;
            }
            if (matchingBeans.size() > 1) {
                String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
                if (primaryBeanName == null) {
                    throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
                }
                if (autowiredBeanNames != null) {
                    autowiredBeanNames.add(primaryBeanName);
                }
                return matchingBeans.get(primaryBeanName);
            }
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(entry.getKey());
            }
            return entry.getValue();
        }
    }

尽管是Array,Collection大概Map,则基于集结类巧月素的项目来進展autowired
by
type(Map使用value的项目)。为啥那样优良管理呢?原本,Spring是为着达到那样的目标:让您能够三遍注入全体切合项指标贯彻,也便是说能够那样子注入:

@Autowired
private List<Car> cars;

一经你的car有多少个落到实处,那么都会注入进来,不会再报

org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No unique bean of type [me.arganzheng.study.spring.autowired.Car] is defined: 
expected single matching bean but found 2: [audi, toyota].

然则,上边的境况只要您用@Resource则不会有这些标题:

public class AutowiredTest extends BaseSpringTestCase {

    @Resource
    @Qualifier("languageChangesMap")
    private Map<String, String> languageChangesMap;

    @Test
    public void testAutowired() {
        assertNotNull(languageChangesMap);
        System.out.println(languageChangesMap.getClass().getSimpleName());
        System.out.println(languageChangesMap);
    }
}

平常运营:

LinkedHashMap
{pt=pt, br=pt, jp=ja, ja=ja, ind=ind, id=ind, en-rin=en-rIn, in=en-rIn, en=en, gb=en, th=th, ar=ar, eg=ar}

当然,你借使不钦命@Qualifier(“languageChangesMap”State of Qatar,同有时间田野name不是languageChangesMap,那么还是同样报错的。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER, lookup=)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 26 more

再正是,@Resource也足以完成地点的List选用全数完结:

public class AutowiredTest extends BaseSpringTestCase {

    @Resource
    @Qualifier("languageChangesMap")
    private Map<String, String> languageChangesMap;

    @Resource
    private List<Car> cars;

    @Test
    public void testAutowired() {
        assertNotNull(languageChangesMap);
        System.out.println(languageChangesMap.getClass().getSimpleName());
        System.out.println(languageChangesMap);

        assertNotNull(cars);
        System.out.println(cars.getClass().getSimpleName());
        System.out.println(cars);
    }
}

运作的妥妥的:

LinkedHashMap
{pt=pt, br=pt, jp=ja, ja=ja, ind=ind, id=ind, en-rin=en-rIn, in=en-rIn, en=en, gb=en, th=th, ar=ar, eg=ar}
ArrayList
[me.arganzheng.study.spring.autowired.Audi@579584da, me.arganzheng.study.spring.autowired.Toyota@19453122]

那是因为@Resource声明使用的是CommonAnnotationBeanPostProcessor微电脑,跟AutowiredAnnotationBeanPostProcessor不是同四个作者[/偷笑]。这里就不深入分析了,感兴趣的同校能够协调看代码商量一下。

末尾结论如下:

1、@Autowired和@Inject

autowired by type 可以 通过@Qualifier 显式指定 autowired by qualifier name(非集合类。注意:不是autowired by bean name!)
如果 autowired by type 失败(找不到或者找到多个实现),则退化为autowired by field name(非集合类)

2、@Resource

默认 autowired by field name
如果 autowired by field name失败,会退化为 autowired by type
可以 通过@Qualifier 显式指定 autowired by qualifier name
如果 autowired by qualifier name失败,会退化为 autowired by field name。但是这时候如果 autowired by field name失败,就不会再退化为autowired by type了

测量检验工程保存在GitHub上,是正规的maven工程,感兴趣的同校可以clone到地点运营测量试验一下。

@Inject使用

利用JSLacrosse-330规范证明

从Spring
3.0开端,提供对JS途锐-330规范注释(正视注入)的支撑。这个注释以与Spring注释相近的主意开展围观。你只要求在你的classpath中有有关的jar。

可以在maven的pom.xml中添加

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
  • 使用@Inject和@Named
    如果你想要使用约束名称作为应注入的正视项,则应接纳@Named注释

import javax.inject.Inject;
import javax.inject.Named;

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}
  • @Named和@ManagedBean:@Component注释的正经等价物
    Instead of @Component, @javax.inject.Named or
    javax.annotation.ManagedBean may be used as follows:

import javax.inject.Inject;
import javax.inject.Named;

@Named("movieListener") // @ManagedBean("movieListener") could be used as well
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

当使用@Named或@ManagedBean时能够接收与运用Spring证明完全相通的机件扫描

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}
  • JS中华V-330评释声明的限量

澳门新葡亰平台官网 3

Spring声明与JSOdyssey-330 标准证明的相比.png

补充

有同事建议Spring官方文书档案上有这么一句话跟本身的结有一点点冲突:

However, although you can use this convention to refer to specific beans by name, @Autowired is fundamentally about type-driven injection with optional semantic qualifiers. This means that qualifier values, even with the bean name fallback, always have narrowing semantics within the set of type matches; they do not semantically express a reference to a unique bean id.

也正是说@Autowired即便加了@Qualifier注脚,其实也是autowired by
type。@Qualifier只是三个节制词,过滤条件而已。重新跟进了一晃代码,发掘真正是那样子的。Spring设计的那么些@Qualifier name 并不平等 bean
name。他多少相通于叁个tag。可是只要那几个tag是并世无两的化,那么实际上效果上等同bean
name。完结上,Spring是先getByType,得到list
candicates,然后再依赖qualifier name进行过滤。

再定义三个Lamborghini,这里运用@Qualifier钦定:

package me.arganzheng.study.spring.autowired;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("luxury")
public class Lamborghini implements Car {

}

再定义二个Rolls-royce,这里故意用@Named内定:

package me.arganzheng.study.spring.autowired;

import javax.inject.Named;

import org.springframework.stereotype.Component;

@Component
@Named("luxury")
public class RollsRoyce implements Car {

}

测验一投注入定义的浮华车:

package me.arganzheng.study.spring.autowired;

import static junit.framework.Assert.assertNotNull;

import java.util.List;

import me.arganzheng.study.BaseSpringTestCase;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * 
 * @author zhengzhibin
 * 
 */
public class AutowiredTest extends BaseSpringTestCase {

    @Autowired
    @Qualifier("luxury")
    private List<Car> luxuryCars;

    @Test
    public void testAutowired() {

        assertNotNull(luxuryCars);
        System.out.println(luxuryCars.getClass().getSimpleName());
        System.out.println(luxuryCars);
    }

}

运维结果如下:

ArrayList
[me.arganzheng.study.spring.autowired.Lamborghini@66b875e1, me.arganzheng.study.spring.autowired.RollsRoyce@58433b76]

补充:Autowiring modes

Spring支持各类autowire格局,当使用XML配置情势时,你能够经过autowire属性钦赐。

no. (Default) No autowiring. Bean references must be defined via a ref element. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system.
byName. Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master, and uses it to set the property.
byType. Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set.
constructor. Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised.

假定选拔@Autowired、@Inject或许@Resource评释的时候,则有一些复杂一些,会有三个退步退化进度,何况引进了Qualifier。然则基本原理是相似。

如下是@Inject的接受,不加@Named表明,须求配备与变量名一致即可。

@Inject
@Named("mongo")
private Mongo mongo;

2、@Autowired

  • org.springframework.bean.factory
  • Spring

@Autowired是Spring提供的笺注,通过AutowiredAnnotationBeanPostProcessor类达成的依据注入,与@inject二者具备可交换性。

@Autowired的使用

@Autowired有个天性为required,能够配备为false,假设安顿为false之后,当未有找到相应bean的时候,系统不会抛错。

@Autowired
private MongoTemplate mongoTemplate;

3、@Resource

  • javax.annotation
  • JSR250 (Common Annotations for Java)

那是JSENVISION250标准的兑现,@Resource通过CommonAnnotationBeanPostProcessor类完结依附注入。

@Resource的使用

@Resource日常会钦命一个name属性,如下:

@Resource(name = "userMapper")
private UserMapper userMapper;

4、四个阐明的相异之处

@Autowired和@Inject基本是相像的,因为双方都以使用AutowiredAnnotationBeanPostProcessor来拍卖依赖注入。但是@Resource是个例外,它应用的是CommonAnnotationBeanPostProcessor来处理信任注入。当然,两个都是BeanPostProcessor。

@Autowired和@Inject

暗许autowired by type,能够经过@Qualifier显式钦命autowired by qualifier
name。

@Resource

暗许autowired by 田野同志 name,假若autowired by 田野先生name战败,会衰退为autowired by type,能够透过@Qualifier显式钦赐autowired
by qualifier name,纵然autowired by qualifier
name败北,会退化为autowired by 田野(fieldState of Qatar name。但是那时候借使autowired by
田野(field卡塔尔 name失败,就不会再退化为autowired by type。

5、总结

村办在运用上,更重申使用@Inject,那是JS福睿斯330规范的兑现,而@Autowired是Spring的贯彻,假如不用Spring经常用不上那一个,而@Resource则是JSKoleos250的贯彻,那是N年前的行业内部。 

 

参考:

(以上内容转今后篇小说)

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图