Spring IOC容器入门(三)
Spring IOC容器的(一)和(二)主要介绍的是Spring IOC的入门使用方法,在实际工作中,Spring通常会使用注解的方式来去掉部分或者全部xml配置,下面介绍一下在Spring中应该如何使用注解来替代xml。
根据Spring对bean对象的管理功能,它提供了四种注解:
-
用于创建对象的注解:xml中的bean标签
-
用于注入属性的注解:xml的property标签
-
用于改变bean作用范围的注解:xml中的scope属性
-
管理bean生命周期的注解:xml的中init-method属性
Spring使用注解时,需要修改xml的命名空间,并且增加一个配置,告诉spring在创建容器的时候,需要到扫描的包,只有在所配置包的里面的类,spring才会去解析这些类上的注解。
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.ws"/>
</beans>
创建bean注解
@Component(value=“test”)注解
该注解的作用就是创建一个配置了该注解的类的一个对象,把他放到spring容器中,这个对象的id就是这个test,这个注解value是可以不需要配置的,如果不配,那么默认使用类的名称,且第一个字母小写。
下面介绍一下Component注解衍生注解,这三个注解的作用和属性与Component注解一样。定义三个注解主要是更清楚的描述相应业务
@Controller 一般用在表现层
@Service 一般用在业务层
@Repository 一般用在持久层
属性注入注解
@Autowired
该注解可以用在属性上,也可以用在方法上,这个注解的原理是首先获取从spring容器中查找与需要注入属性类型相同的bean,如果找到唯一的一个bean,那么就把这个bean注入到该属性上,如果找到的两个类型符合的bean,然后接着去判断这两个类型相同的bean的id的名称哪个与需要注入的属性的名称相同,如果找到就把此bean注入到属性中,如果没有找到那么就报错,使用Autowired注解,不需要提供set方法。
@Qualifier
该注解的作用是在确定了注入类型的情况下,根据bean的ID来注入,它别和Autowired配合使用,由Autowired注解寻找类型,再由Qualifier注解寻找id,具体使用如下: Qualifier的value值表示需要把beanID=ud的bean注入到userDao属性中。
@Autowired
@Qualifier(value = "ud")
private UserDao userDao;
@Resource
由于Qualifier注解需要和Autowired配合使用,因此不方便,spring由提供了一个注解,直接安装bean的id注入。Resource注解的属性不是value而是叫name。
上面的三个注解都是只能注入bean,而基本类型和String的属性需要通过@Value注解注入,集合类型不能通过注解方式注入,只能通过xml方式。
Bean作用范围的注解
@Scope(“prototype”)
采用注解方式创建bean的默认情况下是单例,如果在类上加上@Scope(“prototype”)注解,那么创建的bean就是多例。
Bean生命周期
@PostConstruct
该注解用在方法上,表示对象创建后执行的方法
@PreDestroy
该注解用在方法上,表示bean销毁前执行的方法
上面注解引入方式仍然需要依靠xml配置文件,Spring提供了新的注解,用来替代xml文件。
@Configuration
该注解作用在java类上,表示所修饰的类是一个配置类,相当于xml文件
@ComponentScan
该注意是用来表明spring容器扫描的java包,作用相当于在xml文件配置:
<context:component-scan base-package="com.ws"/>
通常两个注解配合在一起是使用。
@Configuration
@ComponentScan(basePackages = "com.ws.springtest")
public class SpringConf {
}
@Bean
在配置类中定义相应的方法,方法上加上@Bean注解,创建bean,相当于xml中定义bean标签。
@Bean(name="userService")
@Scope("prototype")
public UserService userService(){
return new UserServiceImpl();
}
@Bean注解如果没有配置value属性,那么创建的bean就以@Bean修饰的方法的名称作为Spring IOC容器创建bean的ID,如果在@Bean修饰的方法上增加@Scope注解,可以控制创建的bean是否是单例,还是多例。
当使用注解的方法来替代xml文件的时候,那么需要调用如下的方式来启动Spring IOC容器:
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConf.class);
SpringConf.class就是用@Configuration注解修饰的类。
-- 注意:当创建AnnotationConfigApplicationContext对象是,把SpringConf.class传入到AnnotationConfigApplicationContext时,那么SpringConf类上的@Configuration注解可以省略,因为,使用这种方式Spring会自动去读取传入到AnnotationConfigApplicationContext构造方法的类的信息,会把它当成配置类。AnnotationConfigApplicationContext的构造方法的参数是可变参数,因此可以给它传入多个配置类。只要是传入到它的构造方法中的配置类,那么都不需要在类到的上面增加@Configuration注解,此时这些配置类也不需一定要在@ComponentScan注解所扫描的包里。
@Bean注解修饰的方法如果有参数,那么参数的注入是根据参数的类型到IOC容器中寻找相关的类型的bean,注入到方法的参数中。如果在IOC容器中有类型相同的两个bean,那么就去检查方法参数的名称与哪个bean的id相同,就用哪个bean注入,否则就会报错,为了避免这种错误,可以通过@Qualifier注解来解决这个问题:
@Bean(name="userService")
public UserService userService(@Qualifier("ds1") DataSource dataSource){
return new UserServiceImpl();
}
用@Qualifier注解来指定需要注入的bean的ID。
@Import注解
在使用代码实现spring的bean配置的时候,有时候需要创建多个配置类,每一个配置类完成相应的配置工作。那么,spring如何读取这些配置类呢?
1.把这些配置类传入到AnnotationConfigApplicationContext的构造方法中。此时这些配置类的关系是兄弟关系
2.在配置类上在增加@Configuration注解,并且该配置类必须放在@ComponentScan注解所扫描的包里
2.创建一个主配置类,在主配置类采用1或者2的方式创建,然后通过@Import注解导入其他配置类。这种方式,凡是使用@Import导入的配置类与主配置类就是个父子关系。使用@Import导入的类,既不需要配置@Configuration注解,也不需要把类放置到@ComponentScan注解所扫描的包里。
下面介绍最后两个注解:@PropertySource和@Value
该注解的作用就是读取properties文件,通过@PropertySource把相应路径下的properties文件读到spring容器中,然后通过@Value注解来获取properties文件中的相关key-value值。具体如下:
@PropertySource("classpath:jdbc.properties")
public class JDBCConf {
@Value("${jdbc.uname}")
private String username;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.passwd}")
private String password;
}
其中${} 里的值是properties文件中的key。