Spring Framework 5.0:注解的方式加载Bean之包扫描、@Autowired

本文介绍了Spring框架中使用注解方式进行Bean的配置和管理的方法,包括包扫描、Bean的自动装配及解决装配冲突等问题。

前面我们已经了解到可以有2种方式来加载bean:
XML文件的方式和注解的方式。
http://blog.youkuaiyun.com/github_26672553/article/details/78793707

    public static void main(String[] args) throws Exception{

        // MyConfig类里的代码 好比是我们的xml文件
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

        // 从配置文件中设置好了相关验证
        UserService userService = (UserService)context.getBean("myUserService"); // 这其实就是通过IoC容器的方式 初始化对象
        userService.userLogin("zhangSan","111111111");

    }

AnnotationConfigApplicationContext()其实可以传入多个(打上@Configuration注解的)类。
实际上项目中有很多个这样的配置类是很普遍的。

所以,上面我们硬编码的参数就不太合适了。

注解的方式加载Bean:包扫描

https://docs.spring.io/spring/docs/5.0.1.BUILD-SNAPSHOT/spring-framework-reference/core.html#beans-java-instantiating-container-scan

<beans>
        <context:component-scan base-package="com.acme"/>
</beans>

你也许见过上面这种XML定义的,针对某个package组件扫描。
现在我们并没有采用XML文件定义的方式,如何扫描包(package)?

    public static void main(String[] args) throws Exception{

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.scan("SpringLean"); // 扫描SpringLean这个包
        ctx.refresh();

        UserService userService = (UserService)ctx.getBean("myUserService");
        userService.userLogin("zhangSan","111111111"); // 打印:用户开始登录...
    }

Bean之间相互调用

1、我们创建一个NewsService类,代码如下:

package SpringLean;

public class NewsService {

    // 随便写一个方法吧
    public void showTitle(){
        System.out.println("这是新闻");
    }
}

2、当然为了能够通过注解的方式加载,所以要在MyConfig.java文件中(这个文件就相当于一个XML配置文件),也可以再创建一个这样的文件:

    @Bean
    public NewsService myNewsService(){
        return new NewsService();
    }

我们给myNewsService()方法打上了@Bean这个注解。

3、来到入口函数,测试一把

    public static void main(String[] args) throws Exception{

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.scan("SpringLean"); // 扫描SpringLean这个包
        ctx.refresh();

        NewsService newsService = ctx.getBean("myNewsService",NewsService.class);
        newsService.showTitle(); // 输出:这是新闻
    }

4、上面通过注解的方式加载Bean很好理解,但实际开发是复杂的,我们面临很多需求,比如:如果我们要在NewsService类里怎么调用UserService类呢?

public class NewsService {

    // 随便写一个方法吧
    public void showTitle(){
        System.out.println("这是新闻");

        new UserService(); // 错误
    }
}

难道直接在NewsService类中实例化UserService?肯定不行。
这样搞,对象之间的关联就不在同一个IoC容器里了。

@Autowired

@Autowired注解可以实现自动装配,以实现上面的需求。

package SpringLean;

import org.springframework.beans.factory.annotation.Autowired;

public class NewsService {

    @Autowired
    UserService userService; // 因为在配置类(MyConfig)里有个@bean注解的方法 返回UserService对象,所以这里是可以加载到的

    public void showTitle(){
        System.out.println("这是新闻");

        // 这样就可以在NewsService里 调用到UserService类定义的方法
        try {
            userService.userLogin("zhangSan","111111111");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上面代码就完成了“在NewsService里调用UserService”。
那么实际有没有作用呢?我们需要测试

    public static void main(String[] args) throws Exception{

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.scan("SpringLean"); // 扫描SpringLean这个包
        ctx.refresh();

        NewsService newsService = ctx.getBean("myNewsService",NewsService.class);
        newsService.showTitle(); 
    }

我们在入口函数里只调用了NewsServiceshowTitle()方法(这个方法里会调用UserServiceuserLogin()方法),我们看执行后的控制台输出:

这是新闻
用户开始登录...

5、@Autowired不仅可以作用于属性上,还可以作用于方法上

package SpringLean;

import org.springframework.beans.factory.annotation.Autowired;

public class NewsService {

    UserService userService;

    @Autowired
    public void abc(UserService userService) {
        System.out.println("构造函数被自动执行");
        this.userService = userService;
    }


    public void showTitle(){
        System.out.println("这是新闻");

        // 这样就可以在NewsService里 调用到UserService类定义的方法
        try {
            userService.userLogin("zhangSan","111111111");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行输出:

构造函数被自动执行
这是新闻
用户开始登录...

@Qualifier

1、装配冲突

    @Bean
    public UserService myUserService(){
        UserService userService = new UserService();
        userService.setUserValidateConfig(this.userValidateConfig1());
        return userService;
    }

    @Bean
    public UserService myUS(){
        UserService userService = new UserService();
        userService.setUserValidateConfig(this.userValidateConfig1());
        return userService;
    }

如上面代码我们在MyConfig这个配置类中定义了2个返回UserService对象的方法,这样就会导致在UserService里使用@Autowired装配的时候发生“装配冲突”。
因为Autowired默认是以类型进行装配的,定义了2个同类型的,就不知道到底加载哪个了。

2、

    @Bean
    @Qualifier("us1")
    public UserService myUserService(){
        UserService userService = new UserService();
        userService.setUserValidateConfig(this.userValidateConfig1());
        return userService;
    }

    @Bean
    @Qualifier("us2")
    public UserService myUS(){
        UserService userService = new UserService();
        userService.setUserValidateConfig(this.userValidateConfig1());
        return userService;
    }

我们用不同的Qualifier来区分。

3、这样加载的时候,只需要

    UserService userService;

    @Autowired
    public void abc(@Qualifier("us1") UserService userService) {
        System.out.println("构造函数被自动执行");
        this.userService = userService;
    }

就不会发生冲突了

org.springframework.beans.factory.annotation Annotation Type Autowired @Target (value ={CONSTRUCTOR ,METHOD ,PARAMETER ,FIELD ,ANNOTATION_TYPE }) @Retention (value =RUNTIME ) @Documented public @interface Autowired Marks a constructor, field, setter method, or config method as to be autowired by Spring's dependency injection facilities. This is an alternative to the JSR-330 Inject annotation, adding required-vs-optional semantics. Autowired Constructors Only one constructor of any given bean class may declare this annotation with the required() attribute set to true, indicating the constructor to autowire when used as a Spring bean. Furthermore, if the required attribute is set to true, only a single constructor may be annotated with @Autowired. If multiple non-required constructors declare the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a primary/default constructor (if present) will be used. Similarly, if a class declares multiple constructors but none of them is annotated with @Autowired, then a primary/default constructor (if present) will be used. If a class only declares a single constructor to begin with, it will always be used, even if not annotated. An annotated constructor does not have to be public. Autowired Fields Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public. Autowired Methods Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Such config methods do not have to be public. Autowired Parameters Although @Autowired can technically be declared on individual method or constructor parameters since Spring Framework 5.0, most parts of the framework ignore such declarations. The only part of the core Spring Framework that actively supports autowired parameters is the JUnit Jupiter support in the spring-test module (see the TestContext framework reference documentation for details). Multiple Arguments and 'required' Semantics In the case of a multi-arg constructor or method, the required() attribute is applicable to all arguments. Individual parameters may be declared as Java-8 style Optional or, as of Spring Framework 5.0, also as @Nullable or a not-null parameter type in Kotlin, overriding the base 'required' semantics. Autowiring Arrays, Collections, and Maps In case of an array, Collection , or Map dependency type, the container autowires all beans matching the declared value type. For such purposes, the map keys must be declared as type String which will be resolved to the corresponding bean names. Such a container-provided collection will be ordered, taking into account Ordered and @Order values of the target components, otherwise following their registration order in the container. Alternatively, a single matching target bean may also be a generally typed Collection or Map itself, getting injected as such. Not supported in BeanPostProcessor or BeanFactoryPostProcessor Note that actual injection is performed through a BeanPostProcessor which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation). Since: 2.5 Author: Juergen Hoeller, Mark Fisher, Sam Brannen See Also: AutowiredAnnotationBeanPostProcessor, Qualifier, Value `Autowired` on localhost 提示这个什么意思
最新发布
08-21
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值