Spring基于注解管理bean实现方式讲解
热爱编程的小白白 人气:0一、标记与扫描
①注解
和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。 本质上:所有一切的操作都是 Java 代码来完成的, XML 和注解只是告诉框架中的 Java 代码如何执行。 举例:元旦联欢会要布置教室,蓝色的地方贴上元旦快乐四个字,红色的地方贴上拉花,黄色的地方贴上气球。
班长做了所有标记,同学们来完成具体工作。墙上的标记相当于我们在代码中使用的注解,后面同学们做的工作,相当于框架的具体操作。
②扫描
Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。
③标识组件的常用注解
@Component :将类标识为普通组件
@Controller :将类标识为控制层组件
@Service :将类标识为业务层组件
@Repository :将类标识为持久层组件
问:以上四个注解有什么关系和区别?
通过查看源码我们得知, @Controller 、 @Service 、 @Repository 这三个注解只是在 @Component 注解的基础上起了三个新的名字。
对于 Spring 使用 IOC 容器管理这些组件来说没有区别。所以 @Controller 、 @Service @Repository 这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。 注意:虽然它们本质上一样,但是为了代码的可读性,为了程序结构严谨我们肯定不能随便胡乱标记。
④创建组件
创建控制层组件
@Controller public class UserController { }
创建接口 UserService
public interface UserService { }
创建业务层组件 UserServiceImpl
@Service public class UserServiceImpl implements UserService { }
创建接口 UserDao
public interface UserDao { }
创建持久层组件 UserDaoImpl
@Repository public class UserDaoImpl implements UserDao { }
⑤扫描组件
情况一:最基本的扫描方式(beans里面配置)
<context:component-scan base-package="com.atguigu.spring"> </context:component-scan>
测试:
@Test public void test2(){ ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml"); UserController userController = ioc.getBean(UserController.class); System.out.println(userController); UserDaoImpl userDao = ioc.getBean(UserDaoImpl.class); System.out.println(userDao); UserService userService = ioc.getBean(UserService.class); System.out.println(userService); }
情况二:指定要排除的组件
type="annotation",根据注解排除,expression中设置要排除的注解的全类名:
<!-- context:exclude-filter标签:指定排除规则 --> <!-- type:设置排除或包含的依据 type="annotation",根据注解排除,expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名 --> <context:component-scan base-package="com.atguigu.spring"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
public void test2(){ ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml"); UserController userController = ioc.getBean(UserController.class); System.out.println(userController); UserDaoImpl userDao = ioc.getBean(UserDaoImpl.class); System.out.println(userDao); UserService userService = ioc.getBean(UserService.class); System.out.println(userService); }
将UserController 注释:
public void test2(){ ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml"); // UserController userController = ioc.getBean(UserController.class); // System.out.println(userController); UserDaoImpl userDao = ioc.getBean(UserDaoImpl.class); System.out.println(userDao); UserService userService = ioc.getBean(UserService.class); System.out.println(userService); }
type="assignable",根据类型排除,expression中设置要排除的类型的全类名 :
<context:component-scan base-package="com.atguigu.spring"> <!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>--> <context:exclude-filter type="assignable" expression="com.atguigu.spring.Dao.impl.UserDaoImpl"/> </context:component-scan>
public void test2(){ ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml"); UserController userController = ioc.getBean(UserController.class); System.out.println(userController); UserDaoImpl userDao = ioc.getBean(UserDaoImpl.class); System.out.println(userDao); UserService userService = ioc.getBean(UserService.class); System.out.println(userService); }
将UserDaoImpl 注释掉:
public void test2(){ ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml"); UserController userController = ioc.getBean(UserController.class); System.out.println(userController); // UserDaoImpl userDao = ioc.getBean(UserDaoImpl.class); // System.out.println(userDao); UserService userService = ioc.getBean(UserService.class); System.out.println(userService); }
情况三:仅扫描指定组件
<context:component-scan base-package="com.atguigu" use-default-filters="false"> <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 --> <!-- use-default-filters属性:取值false表示关闭默认扫描规则 --> <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 --> <!-- type:设置排除或包含的依据 type="annotation",根据注解排除,expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名 --> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--<context:include-filter type="assignable" expression="com.atguigu.controller.UserController"/>--> </context:component-scan>
⑥组件所对应的 bean 的 id 在我们使用 XML 方式管理 bean 的时候,每个 bean 都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
默认情况
类名首字母小写就是 bean 的 id 。例如: UserController 类对应的 bean 的 id 就 userController 。
自定义 bean 的 id
可通过标识组件的注解的 value 属性设置自定义的 bean 的 id
@Service("userService")
// 默认为 userServiceImpl
public class UserServiceImpl implements UserService {}
public void test2(){ ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire-xml.xml"); UserController userController = ioc.getBean("userController",UserController.class); System.out.println(userController); UserDao userDao = ioc.getBean("userDaoImpl",UserDao.class); System.out.println(userDao); UserService userService = ioc.getBean("userServiceImpl",UserService.class); System.out.println(userService); }
二、基于注解的自动装配
①场景模拟
参考基于 xml 的自动装配
在 UserController 中声明 UserService 对象
在 UserServiceImpl 中声明 UserDao 对象
②@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("保存成功"); } }
③@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(); } }
④@Autowired工作流程
首先根据所需要的组件类型到 IOC 容器中查找
- 能够找到唯一的bean:直接执行装配
- 如果完全找不到匹配这个类型的bean:装配失败
- 和所需类型匹配的bean不止一个
→没有@Qualifier注解:根据@Autowired标记位置成员变量的变量名作为bean的id进行匹配
能够找到:执行装配
找不到:装配失败
→使用@Qualifier 注解:根据 @Qualifier 注解中指定的名称作为 bean 的 id 进行匹配
能够找到:执行装配
找不到:装配失败
@Controller public class UserController { @Autowired @Qualifier("userServiceImpl") private UserService userService; public void saveUser(){ userService.saveUser(); } }
@Autowired中有属性required,默认值为true,因此在自动装配无法找到相应的bean时,会装配失败
可以将属性 required 的值设置为 true ,则表示能装就装,装不上就不装,此时自动装配的属性为默认值
但是实际开发时,基本上所有需要装配组件的地方都是必须装配的,用不上这个属性。
加载全部内容