1.8 spring中的自动装配



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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值