文章目录
1.概念
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
2.IOC 实现层级代码搭建
层级代码结构: Controller,Service,Dao
创建类UserController
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void saveUser(){
userService.saveUser();
}
}
创建接口UserService
public interface UserService {
void saveUser();
}
创建类UserServiceImpl实现接口UserService
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void saveUser() {
userDao.saveUser();
}
}
创建接口UserDao
public interface UserDao {
void saveUser();
}
创建类UserDaoImpl实现接口UserDao
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
3.ByType 自动装配
3.1 自动装配说明
使用bean标签的autowire属性设置自动装配效果,其自动装配方式为byType
byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
- 若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null
- 若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常
NoUniqueBeanDefinitionException
3.2 编辑配置文件
<!--自动装配类型 调用set方法为属性赋值
autowire="default" autowire="no" 表示不会自动装配 以默认值为准
autowire="byType" 根据类型自动装配
-->
<bean id="userController" class="com.atguigu.controller.UserController" autowire="byType"/>
<bean id="userService" class="com.atguigu.service.UserServiceImpl" autowire="byType"/>
<bean id="userDao" class="com.atguigu.dao.UserDaoImpl"/>
4.ByName 自动装配
4.1 根据名称自动装配
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
注意事项:
- 一般条件下 默认使用byType 根据类型匹配.
- 如果配置文件中有同类型的Bean 则可以使用byName进行区分
4.2 编辑配置文件
<bean id="userController" class="com.atguigu.controller.UserController" autowire="byName"/>
<bean id="userService11" class="com.atguigu.service.UserServiceImpl" autowire="byName"/>
<bean id="userDao11" class="com.atguigu.dao.UserDaoImpl"/>
5.基于注解管理bean
5.1 关于注解介绍
和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。在本质上,所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。
例如我们元旦联欢会要布置教室,蓝色的地方贴上元旦快乐四个字,红色的地方贴上拉花,黄色的地方贴上气球。
班长做了所有标记,同学们来完成具体工作。墙上的标记相当于我们在代码中使用的注解,后面同学们做的工作,相当于框架的具体操作。
5.2 常用注解
@Component
:将类标识为普通组件@Controller
:将类标识为控制层组件@Service
:将类标识为业务层组件@Repository
:将类标识为持久层组件
通过查看源码我们得知,@Controller
、@Service
、@Repository
这三个注解只是在@Component注解
的基础上起了三个新的名字。
对于Spring使用IOC容器管理这些组件来说没有区别。所以@Controller
、@Service
、@Repository
这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。
注意:虽然它们本质上一样,但是为了代码的可读性,为了程序结构严谨我们肯定不能随便胡乱标记。
5.3 组件扫描方式
Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。
5.3.1 基本扫描方式
<!--指定包扫描路径 会扫描其子孙包数据...-->
<context:component-scan base-package="com.atguigu"/>
测试类:
@Test
public void testUser() throws SQLException {
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = applicationContext.getBean(UserController.class);
UserService userService = applicationContext.getBean(UserService.class);
UserDao userDao = applicationContext.getBean(UserDao.class);
System.out.println(userController);
System.out.println(userService);
System.out.println(userDao);
}
5.3.2 排除指定的组件
在SpringMVC中可能只扫描Controller层, 而Spring框架负责扫描 Service/Dao层 如何才能解决重复扫描的问题呢?
<!--指定包扫描路径-->
<context:component-scan base-package="com.atguigu">
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="assignable" expression="com.atguigu.service.UserServiceImpl"/>
</context:component-scan>
5.3.3 加载指定的组件
<!--指定包扫描路径
use-default-filters="false" 默认包扫描失效
use-default-filters="true" 开启默认包扫描
-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="aspectj" expression="com.atguigu.service.UserServiceImpl"/>-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
指定测试类
@Test
public void testUser() throws SQLException {
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = applicationContext.getBean(UserController.class);
//UserService userService = applicationContext.getBean(UserService.class);
UserDao userDao = applicationContext.getBean(UserDao.class);
System.out.println(userController);
//System.out.println(userService);
System.out.println(userDao);
}
5.3.4 管理Bean的Id
在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
默认情况下,类名首字母小写就是bean的id。例如:UserController类对应的bean的id就是userController。
也可通过标识组件的注解的value属性设置自定义的bean的id
@Service(“userService”) //默认为userServiceImpl
public class UserServiceImpl implements UserService {}
6.基于注解的自动装配
6.1 代码基本结构
在UserController中声明UserService对象
在UserServiceImpl中声明UserDao对象
6.2 @Autowired注解
在成员变量上直接标记@Autowired注解
即可完成自动装配,不需要提供setXxx()方法。以后我们在项目中的正式用法就是这样。
@Controller
public class UserController {
@Autowired
private UserService userService;
public void saveUser(){
userService.saveUser();
}
}
public interface UserService {
void saveUser();
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void saveUser() {
userDao.saveUser();
}
}
public interface UserDao {
void saveUser();
}
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
6.3 @Autowired 额外配置
说明: @Autowired注解
可以标记在构造器和set方法上,此时它们可以用来自动装配依赖项。
@Controller
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService){
this.userService = userService;
}
public void saveUser(){
userService.saveUser();
}
}
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
public void saveUser(){
userService.saveUser();
}
}
6.4 @Autowired工作流程
首先根据所需要的组件类型到IOC容器中查找
- 首先根据类型匹配,如果找到直接注入找不到对象按照Id进行匹配
- 如果按照Id能找到对象 则注入,找不到则报错.
- 如果使用
@Qualifier注解
则强制使用Id进行注入
6.5 @Qualifier注解说明
@Qualifier注解
是Spring框架中的一个注解,用于解决依赖注入时的歧义性问题。当一个接口或类有多个实现时,使用@Qualifier注解
可以指定注入的具体实现类。
在Spring中,使用@Autowired注解
进行自动装配时,如果存在多个符合条件的候选对象,则会抛出NoUniqueBeanDefinitionException异常
。为了解决这个问题,可以在@Autowired注解
之前使用@Qualifier注解
,并指定要注入的具体实现类的bean名称。
public interface Animal {
void sound();
}
@Component
@Qualifier("cat")
public class Cat implements Animal {
@Override
public void sound() {
System.out.println("Meow");
}
}
@Component
@Qualifier("dog")
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("Woof");
}
}
@Component
public class AnimalService {
private final Animal animal;
public AnimalService(@Qualifier("cat") Animal animal) {
this.animal = animal;
}
public void makeSound() {
animal.sound();
}
}
在上述示例中,AnimalService类中通过@Qualifier(“cat”)注解指定了要注入的Animal实现类是Cat。