1、注解装配Bean介绍
通过前面的学习,我们已经知道如何通过XML的方式去装配Bean了,但是我们在实际的开发中,为了简化开发,更多的时候会使用到注解(annotation)的方式来装配Bean。因为注解可以大量减少繁琐的XML配置,并且注解的功能更为强大,它既能实现XML的功能,也提供了自动装配的功能,更加有利于开发,这就是“约定优于配置”原则,简称CoC(Convention over Configuration)。Spring提供了两种方式让Spring IOC容器发现Bean:
- 组件扫描:通过定义资源的方式,让Spring IOC容器扫描资源所在的包,从而装配Bean。
- 自动装配:通过注解自动找到依赖关系中所需要的Bean。
所以在后面的学习中都会以注解为主,注意这里只是主,而不是全部以注解的方式去实现。因为在实际的开发中是不会全部使用注解去开发,都是两种方式结合,一般使用XML注册Bean,比如加载数据库的连接文件时,一般会在XML中配置,因为这些公共配置文件使用注解配置会很分散,也不方便更改维护,不便于统一管理。而属性的注入都使用注解,所以是以注解为主,以XML为辅。本章先来总结一下组件扫描方式,然后下一篇文章总结使用注解进行自动装配。
2、使用@Compoent注解装配Bean
我们来看之前的User类,并用@Component进行装配:
/** * 用户实体类 */ @Component(value = "user") public class User { @Value(value = "2020") private int userId; @Value(value = "是菜逼唐") private String userName; @Value(value = "20") private int userAge; @Value(value = "123456") private String userPwd; @Value(value = "地球中国北京") private String userAddress; //女朋友(装配对象这里下一章介绍--使用注解自动装配) private GirlFriend girlFriend; //getter、setter、toString方法省略...... }
下面来介绍一下@Component和@Value注解:
- @Component:相当于<bean id="" class=""/>,这个注解表示Spring 容器会把这个类扫描成一个Bean实例,其中value属性代表这个类在 Spring 中的 id,相当于XML方式中定义的 Bean 的 id :<bean id="user" class="com.thr.pojo.User">,我们也可以直接简写成@Component("user"),甚至直接写成@Component,如果不写的话,默认以类名的首字母小写的形式作为 id 配置到容器中。
- @Value:相当于<property name="" value=""/>,这个注解表示注入一个值,但是这里只是一个简单值,如果是注入一个对象得用另一个注解(@Autowired),后面在注解自动装配时会介绍。
然后我们在applicationContext.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 https://www.springframework.org/schema/context/spring-context.xsd"> <!--组件自动扫描,指定注解扫描包路径--> <!-- base-package放的是包名,有多个包名中间用逗号隔开 --> <context:component-scan base-package="com.thr.pojo"/> </beans>
注意:这里是要引入context的命名空间的:
测试代码:
/** * 测试代码 */ public class SpringTest { public static void main(String[] args) { //1.初始化Spring容器,加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.通过容器获取实例,getBean()方法中的参数是bean标签中的id User user = applicationContext.getBean("user", User.class); //3.调用实例中的属性 System.out.println(user.getUserId()+"----"+ user.getUserName()+"----"+ user.getUserAge()+"----"+ user.getGirlFriend()); } }
运行测试代码,查看控制台打印结果:
特别注意:上面是一个最基本的Component注入的简单例子,除了@Component外,Spring提供了3个功能基本和@Component等效的注解:
- @Repository:用于对DAO实现类进行标注
- @Service:用于对Service实现类进行标注
- @Controller:用于对Controller实现类进行标注
3、使用注解扫描@ComponentScan
我们也可以不在applicationContext.xml配置文件中配置组件扫描,而是直接使用注解扫描,所以我们将xml配置文件的配置去掉:
那么接下来要怎么做呢?这个时候我们需要用一个JavaConfig来告诉 Spring 容器怎么扫描,如下:
package com.thr.pojo; import org.springframework.context.annotation.ComponentScan; /** * 组件扫描注解 */ @ComponentScan public class PojoConfig { }
这个类十分简单,没有任何逻辑,但是需要说明两点:
- Config类必须和所扫描类的包名一致,例如这里必须在com.thr.pojo下。
- @ComponentScan注解表示对组件进行扫描,默认是扫描当前包的路径,如果不在则扫描不到。
然后就可以使用 Spring IOC容器的实现类AnnotationConfigApplicationContext 去生成 IOC 容器了,代码如下所示:
/** * 测试代码 */ public class SpringTest1 { public static void main(String[] args) { //1.初始化Spring容器,通过注解加载 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PojoConfig.class); //2.通过容器获取实例 User user = applicationContext.getBean("user", User.class); //3.调用实例中的属性 System.out.println(user.getUserId()+"----"+ user.getUserName()+"----"+ user.getUserAge()+"----"+ user.getGirlFriend()); } }
这里可以看到使用了 AnnotationConfigApplicationContext 类去初始化 Spring IoC 容器,它的配置项是 PojoConfig 类,这样 Spring IoC 就会根据注解的配置去解析对应的资源,来生成 IoC 容器了。但是这就有个弊端,一般来说我们的资源不会全部放在同一个包下,而对于 @ComponentScan 注解,它只是扫描所在包的 Java 类,这就意味着要进行全局扫描,这可怎么办呢?还好这个注解它有两个属性配置项basePackages和basePackageClasses:
- basePackages:表示扫描的包路径,可以是多个。
- basePackageClasses:表示扫描的类,也可以配置多个。
这样我们就不用关心配置类是否和被扫描资源在同一个包下的问题了。
然后我们来重构之前写的 PojoConfig 类来验证上面两个属性配置项,首先我们将PojoConfig类移到另一个包下如com.thr.config,代码如下。
package com.thr.pojo; import org.springframework.context.annotation.ComponentScan; /** * 组件扫描注解(三选一) */ //@ComponentScan(basePackages = "com.thr.pojo") //@ComponentScan(basePackageClasses =User.class) @ComponentScan(basePackages = "com.thr.pojo",basePackageClasses = User.class) public class PojoConfig { }
如果有多个包或类,我们用大括号包起来然后在大括号里面用逗号隔开,简单举例:
@ComponentScan(basePackages = {"package1","package3","package4"}) @ComponentScan(basePackageClasses ={Class1.class,Class2.class,Class3.class})
这样 Spring 容器就能将一个类装配成Bean了。最后我们来看一下结果吧。