1.@Autowired、@Qualifier、@Primary注解
1.1.@Autowired注解
@Autowired注解可以对类成员变量、方法和构造函数进行标注,完成自动装配的工作。
package org.springframework.beans.factory.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {boolean required() default true;
}
@Autowired注解说明:
- @Autowired注解默认是优先按照类型去容器中找对应的组件,若找到则就赋值,相当于是调用了如下这个方法:
applicationContext.getBean(类名.class);
- 如果找到多个相同类型的组件,那么是将属性名称作为组件的id,到IOC容器中进行查找,这时就相当于是调用了如下这个方法:
applicationContext.getBean("组件的id");
1.2.@Qualifier注解
@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,那么就需要配合@Qualifier注解来使用了。
@Qualifier注解的源码,如下所示:
package org.springframework.beans.factory.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {String value() default "";}
1.3.@Primary注解
在Spring中使用注解时,常常会使用到@Autowired这个注解,它默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口而言,可能会有几种不同的实现类,而在默认只会采取其中一种实现的情况下,就可以使用@Primary注解来标注优先使用哪一个实现类。
package org.springframework.context.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {}
2.自动装配
Spring组件的自动装配就是Spring利用依赖注入,也就是我们通常所说的DI,完成对IOC容器中各个组件的依赖关系赋值。
3.程序案例
3.1.测试@Autowired注解
3.1.1.测试1
创建BookDao、BookService、BookServiceImpl和BookController
- BookDao
package com.tianxia.springannotation.dao;import org.springframework.stereotype.Repository;/*** BookDao* @author liqb* @date 2023-04-21 16:37**/ // 名字默认是类名首字母小写 @Repository public class BookDao { }
- BookService
package com.tianxia.springannotation.service;/*** BookService* @author liqb* @date 2023-04-21 16:38**/ public interface BookService { }
- BookServiceImpl
package com.tianxia.springannotation.service.impl;import com.tianxia.springannotation.dao.BookDao; import com.tianxia.springannotation.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;/*** BookServiceImpl* @author liqb* @date 2023-04-21 16:38**/ @Service public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;/*** 打印方法* @author liqb* @date 2023-05-06 13:09*/public void print() {System.out.println(bookDao);}@Overridepublic String toString() {return "BookService [bookDao=" + bookDao + "]";} }
- BookController
package com.tianxia.springannotation.controller;import com.tianxia.springannotation.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller;/*** BookController* @author liqb* @date 2023-04-21 16:39**/ @Controller public class BookController {@Autowiredprivate BookService bookService; }
为了更好的看到效果,在项目的config包下创建MainConfigOfAutowired配置类,如下所示:
package com.tianxia.springannotation.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** 配置类* @author liqb* @date 2023-05-06 13:11**/
@Configuration
@ComponentScan({"com.tianxia.springannotation.service", "com.tianxia.springannotation.dao", "com.tianxia.springannotation.controller"})
public class MainConfigOfAutowired {
}
运行测试方法,输出结果如下所示:
/*** 测试方法* @author liqb* @date 2023-05-06 13:14*/
@Test
public void test01() {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);BookService bookService = applicationContext.getBean(BookService.class);System.out.println(bookService);BookDao bookDao = applicationContext.getBean(BookDao.class);System.out.println(bookDao);applicationContext.close();
}
BookService类中使用@Autowired注解注入的BookDao对象和直接从IOC容器中获取的BookDao对象是同一个对象
3.1.2.测试2
在Spring容器中存在对多个BookDao对象,那么这时又该如何处理
对BookDao类进行改造,为其加上一个lable字段,并为其赋一个默认值,如下所示。
package com.tianxia.springannotation.dao;import org.springframework.stereotype.Repository;/*** BookDao* @author liqb* @date 2023-04-21 16:37**/
// 名字默认是类名首字母小写
@Repository
public class BookDao {private String lable = "1";public String getLable() {return lable;}public void setLable(String lable) {this.lable = lable;}@Overridepublic String toString() {return "BookDao [lable=" + lable + "]";}
}
在MainConfigOfAutowired配置类中注入一个BookDao对象,并且显示指定该对象在IOC容器中的bean的名称为bookDao2,并还为该对象的lable字段赋值为2
package com.tianxia.springannotation.config;import com.tianxia.springannotation.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** 配置类* @author liqb* @date 2023-05-06 13:11**/
@Configuration
@ComponentScan({"com.tianxia.springannotation.service", "com.tianxia.springannotation.dao", "com.tianxia.springannotation.controller"})
public class MainConfigOfAutowired {/*** 注入bookDao对象* @author liqb* @date 2023-05-06 13:27* @return*/@Bean("bookDao2")public BookDao bookDao() {BookDao bookDao = new BookDao();bookDao.setLable("2");return bookDao;}
}
运行测试方法,输出结果如下所示:
/*** 测试方法* @author liqb* @date 2023-05-06 13:14*/
@Test
public void test01() {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);BookService bookService = applicationContext.getBean(BookService.class);System.out.println(bookService);applicationContext.close();
}
结果信息输出了lable=1,说明,@Autowired注解默认是优先按照类型去容器中找对应的组件,找到就赋值;如果找到多个相同类型的组件,那么再将属性的名称作为组件的id,到IOC容器中进行查找。
让@Autowired注解装配bookDao2
将BookService类中的bookDao属性的名称全部修改为bookDao2即可,如下所示:
package com.tianxia.springannotation.service.impl;import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** BookServiceImpl* @author liqb* @date 2023-04-21 16:38**/
@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao2;/*** 打印方法* @author liqb* @date 2023-05-06 13:09*/public void print() {System.out.println(bookDao2);}@Overridepublic String toString() {return "BookService [bookDao=" + bookDao2 + "]";}
}
运行测试方法,输出结果如下所示:
结论:@Autowired注解默认是优先按照类型去容器中找对应的组件,找到就赋值;如果找到多个相同类型的组件,那么再将属性的名称作为组件的id,到IOC容器中进行查找。
3.1.3.测试3
@Autowired注解属性required
required=false这个玩意的意思就是说找到就装配,找不到就拉到,就别装配了
require= true,未找到相应的bean对象,Spring就会抛出了异常
package com.tianxia.springannotation.service.impl;import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** BookServiceImpl* @author liqb* @date 2023-04-21 16:38**/
@Service
public class BookServiceImpl implements BookService {@Autowired(required = false)private BookDao bookDao2;/*** 打印方法* @author liqb* @date 2023-05-06 13:09*/public void print() {System.out.println(bookDao2);}@Overridepublic String toString() {return "BookService [bookDao=" + bookDao2 + "]";}
}
3.2.测试@Qualifier注解
显示指定@Autowired注解装配哪个组件
package com.tianxia.springannotation.service.impl;import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;/*** BookServiceImpl* @author liqb* @date 2023-04-21 16:38**/
@Service
public class BookServiceImpl implements BookService {@Autowired@Qualifier("bookDao")private BookDao bookDao2;/*** 打印方法* @author liqb* @date 2023-05-06 13:09*/public void print() {System.out.println(bookDao2);}@Overridepublic String toString() {return "BookService [bookDao=" + bookDao2 + "]";}
}
运行测试方法,输出结果如下所示:
此时尽管字段的名称为bookDao2,但是使用了@Qualifier注解显示指定了@Autowired注解装配bookDao对象,所以,最终的结果中输出了bookDao对象的信息。
3.3.测试@Primary注解
在Spring中,对同一个接口而言,可能会有几种不同的实现类,而默认只会采取其中一种实现的情况下,就可以使用@Primary注解来标注优先使用哪一个实现类。
在MainConfigOfAutowired配置类的bookDao()方法上添加上@Primary注解,如下所示:
package com.tianxia.springannotation.config;import com.tianxia.springannotation.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;/*** 配置类* @author liqb* @date 2023-05-06 13:11**/
@Configuration
@ComponentScan({"com.tianxia.springannotation.service", "com.tianxia.springannotation.dao", "com.tianxia.springannotation.controller"})
public class MainConfigOfAutowired {/*** 注入bookDao对象* @author liqb* @date 2023-05-06 13:27* @return*/@Primary@Bean("bookDao2")public BookDao bookDao() {BookDao bookDao = new BookDao();bookDao.setLable("2");return bookDao;}
}
注释掉BookService类中bookDao字段上的@Qualifier注解
package com.tianxia.springannotation.service.impl;import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;/*** BookServiceImpl* @author liqb* @date 2023-04-21 16:38**/
@Service
public class BookServiceImpl implements BookService {// @Qualifier("bookDao")@Autowired(required = false)private BookDao bookDao2;/*** 打印方法* @author liqb* @date 2023-05-06 13:09*/public void print() {System.out.println(bookDao2);}@Overridepublic String toString() {return "BookService [bookDao=" + bookDao2 + "]";}
}
运行测试方法,输出结果如下所示:
此时lable的值为2,这说明装配了MainConfigOfAutowired配置类中注入的bookDao2