导读:
我们在刚开始进行spring的学习时, 大部分都是在applicationContext.xm的配置文件中向IOC容器中注入bean,但是这种方式实在是有点麻烦,所以从spring的2.5版本开始就引入注解的方式来帮助我们简化bean的配置,而现在spring版本已经升级到5.0以上了,使用注解的方式来进行配置bean已经越来越普遍,在springboot中更是没有了applicationContext.xml的配置文件,都是采用注解的方式来进行IOC的注入,所以了解如何用注解来进行bean的配置变得很重要了。
IOC相关的注解
@Configuration注解
作用:在applicationContext.xml配置文件中我们配置bean都是在<beans></beans>标签中进行的,而在纯注解的配置中我们不需要applicationContext.xml这个文件,所以在这里Configuration注解就相当于applicationContext.xml中的beans标签
使用: 在一个类前加上这个注解即可,该类就相当于一个beans标签了
//该类就相当于一个空的beans标签了
@Configuration
public class UserDao {
}
启动容器
与通过配置文件启动容器的方式相同,只不过是使用AnnotationConfigApplicationContext这个实现类传入字节码对象即可
public class Main {
public static void main(String[] args) {
//传入@Configuration注解所在类的Class对象
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserDao.class);
}
}
@ComponentScan注解(包扫描注解)
作用: 我们在使用配置注解(比如@Autowired,@Component等注解,下面会讲)时, 如果我们只是在一个方法或者类前写一个注解,那么spring怎么知道我们要将哪个类交给IOC容器管理呢,所以这个注解的作用就是告诉spring要扫描哪些包下的类,将这些配置了注解的类交给IOC容器管理
使用: 在添加了@Configuration的注解类前加上此注解, 并且指定basePackages属性的值即可.
@Configuration
//basePackages为一个字符串数组,指定要进行扫描的包
@ComponentScan(basePackages = {包1, 包2, .....})
public class UserDao {
}
@Component注解
作用:将一个类注入IOC容器中,相当于先前配置文件中的bean标签
使用: 在一个类前加上此注解即可, 有一个value参数,作用是指定注入类的名称,相当于bean标签中的id属性.也可以省略不写,默认为类名首字母小写名称,例如Plant类的默认名称为plant
//将Animal类交给IOC容器管理
@Component(value = "animals")
public class Animal {
public Animal(){
System.out.println("Animal is creating....");
}
}
@Controller,@Service,@Repository注解
与上面的@Component注解作用与用法一样,只是帮助我们标识此类在项目中的层面罢了,
@Controller常用于控制层(其实在后面的web开发中,被它修饰的类中的方法默认都是一个Servlet,现在了解即可),@Service用于业务层,@Repository用于数据操作层。
@Scope注解
作用:指定类的制造方式为单例还是单例
使用:放置在类前面即可,指定为单例还是多例模式
@Component(value = "animals")
@Scope("singleton")//或者prototype
public class Animal {
public Animal(){
System.out.println("Animal is creating....");
}
}
@PostConstruct,@PreDestroy注解
作用:为一个类指定初始化(@PostConstruct)或者销毁(@PreDestroy)方法,相当于bean标签中的init-method和destroy-method方法
使用:在一个想要充当初始化或者销毁方法的方法前添加此注解
@Component(value = "animals")
public class Animal {
public Animal(){
System.out.println("Animal is creating....");
}
//初始化方法
@PostConstruct
public void init(){
System.out.println("Animal is initializing...");
}
//销毁方法
@PreDestroy
public void destroy(){
System.out.println("Animal is destroying");
}
}
测试:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserDao.class);
Animal animal = applicationContext.getBean(Animal.class);
//在退出虚拟机之前销毁IOC容器
applicationContext.registerShutdownHook();
}
}
结果:
Animal is creating....
Animal is initializing...
Animal is destroying
进程已结束,退出代码0
DI相关注解
@Autowired,@Resource, @Qualifier(需配合Autowired注解使用)注解
作用: 这些注解都是用来自动装配引用类型的注解,装配的bean必须在IOC容器中存在
使用: 在一个setter或者字段名之前都可以添加使用.
//新建一个Person类,Person类有一个类型为Animal的字段animal
public class Person {
//添加到字段之前也是可以的
// @Autowired
private Animal animal;
public Person(){
System.out.println("Person is creating....");
}
//setter方法前也可以,自动装配该字段
@Autowired
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
区别:
@Autowired:
@Autowired注解是默认首先按照类型装配的(byType),如果找不到对应类型的bean或者找到多个类型相同的bean,则再按照名称进行装配(byName)。如果想直接指定名称进行装配则需要配合@Qualifier注解进行使用:
首先我们创建两个类型一样的bean,一个为animal,一个为animal1

然后我们在字段animals前添加此注解,由于@Autowired先根据类型进行装配,但是IOC中有两个类型相同的bean(animal和animal1),如前面所说,当找到多个类型的bean时,@Autowired注解会按照名称进行装配,所以这里就会按照bean的名称进行装配,但是这里变量的名称为animals,而两个bean的名称为animal和animal1(与变量名称不同,因为是按名称装配所以装配不成功),所以这里就会报错
@Component
public class Person {
@Autowired
private Animal animals;
public Person(){
System.out.println("Person is creating....");
}
public void printAnimal(){
//打印自动装配的animals
System.out.println("animal is" + animals);
}
}
开启测试:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserDao.class);
Person person = applicationContext.getBean(Person.class);
person.printAnimal();
}
}
结果:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person': Unsatisfied dependency expressed through field 'animal1s'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn_java_factory.Animal' available: expected single matching bean but found 2: animal,animal1
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person': Unsatisfied dependency expressed through field 'animal1s'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn_java_factory.Animal' available: expected single matching bean but found 2: animal,animal1
但是我们只要将字段名改为"animal"或者"animal1"就会运行成功
@Autowired
//animal1或者animal都可以
private Animal animal;
结果:
Person is creating....
animal iscn_java_factory.Animal@3b69e7d1
进程已结束,退出代码0
还可以直接为@Autowired注解指定以名称进行装配,这时就要使用@Qualifier注解,例如:
@Autowired
@Qualifier("animal")
private Animal myAnimal;
我们这里使用@Qualifier注解指定@Autowired以指定名称进行装配(@Qualifier必须配合@Autowired使用),所以@Autowired会找到名称为"animal"的bean装配给myAnimal这个属性。
@Resource
@Resource注解如果没有指定name和type属性则默认以名称进行装配,当注解写在字段上时,默认取字段名为指定名称,如果没有找到对应的bean,则再以类型进行自动装配,如果找不到或者找到多个同一类型的bean则报错;如果指定name属性则只会按照名称进行装配,没有找到指定的名称则报错,如果指定type属性则只会按照类型进行装配,如果找不到或者找到多个同一类型的bean则报错;
@Value注解
作用:给简单类型字段进行赋值
使用:在简单类型字段前添加即可
@Component
public class Person {
//为String类型赋值
@Value("jack")
private String username;
@Value("20")
private int age;
public Person(){
System.out.println("Person is creating....");
}
public void print(){
System.out.println("username is " + username + ", age " + age);
}
}
测试:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserDao.class);
Person person = applicationContext.getBean(Person.class);
person.print();
}
}
结果:
Person is creating....
username is jack, age 20
进程已结束,退出代码0
可以看出值已经注入进去了;
@Value还可以读取properties配置文件中的值:
1.通过@PropertySource注解将properties文件加载进来
@Configuration
@ComponentScan(basePackages = {"cn_java_factory"})
//info.properties为在resources文件夹下的配置文件,最好加上"classpath:"这个前缀
@PropertySource("classpath:info.properties")
public class UserDao {
}
2.通过${属性名}进行引用
@Component
public class Person {
//hobby为info.properties中的属性名
@Value("${hobby}")
private String hobby;
@Value("${weight}")
private int weight;
@Value("${height}")
private double height;
public Person(){
System.out.println("Person is creating....");
}
public void print(){
System.out.println("weight " + weight + " height" + height + " hobby " + hobby);
}
}
@Bean注解
作用: 将静态工厂方法或者实例工厂方法的返回对象注入到IOC容器中
使用: 在工厂方法前加上此注解即可,可通过value指定bean的名称,如果不进行指定的话默认为方法名名称。
@Configuration
@ComponentScan(basePackages = {"cn_java_factory"})
@PropertySource("classpath:info.properties")
public class UserDao {
//静态工厂
@Bean("animals")
public static Animal getAnimal(){
return new Animal();
}
//实例工厂
@Bean
public Person getPerson(){
return new Person();
}
}
从下图可以看出@Bean如果没有指定value值则会使用方法名作为bean的名称,并且已经成功的将工厂方法产生的对象注入到IOC容器中了

@Import注解
当我们在被@Configuratin注解修饰的类中写多个被@Bean修饰的工厂方法时,可能会使修饰的类变得臃肿庞大,所以我们可以通过@Import注解将其它类中的被@Bean修饰的方法名引入进来来.
@Configuration
@ComponentScan(basePackages = {"cn_java_factory"})
@PropertySource("classpath:info.properties")
//引入其它类中的被@Bean修饰的工厂方法
@Import(PersonFactory.class)
public class UserDao {
}
PersonFactory类:
public class PersonFactory{
//静态工厂
@Bean("animals")
public static Animal getAnimal(){
return new Animal();
}
//实例工厂
@Bean
public Person getPerson(){
return new Person();
}
}
结果:

可以看出工厂方法返回的对象也被注入到IOC中了
上面这些注解就是我们在spring配置中常用的注解了,感谢您的阅读!!