目录
一、基于注解管理Bean(重点)
1.1、概述
简介
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。
步骤
- 引入依赖
- 开启组件扫描
- 使用注解定义 Bean
- 依赖注入
使用注解
Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean
1.2、开启组件扫描
概述
Spring 默认不支持注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 context:component-scan 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。
-
步骤一:添加约束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> </beans>
-
步骤二:开启扫描方式
<context:component-scan base-package="com.atguigu.spring6"> </context:component-scan>
1.2.1、指定要排除的组件
<context:exclude-filter></context:exclude-filter>
标签,指定排除规则
- type属性:设置排除或包含的依据
- annotation,根据注解排除
- assignable,根据类型排除
- expression属性:设置要排除的注解或类型的全类名
<context:component-scan base-package="com.atguigu.spring6">
<!-- context:exclude-filter标签:指定排除规则 -->
<!--
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.spring6.controller.UserController"/>-->
</context:component-scan>
1.2.2、仅扫描指定组件
use-default-filters="false"
,表示关闭默认扫描规则<context:include-filter></context:include-filter>
,表示指定的过滤条件来确定哪些类应该被包含在组件扫描中
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>
1.3、使用注解定义Bean
Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean
1.4、使用@Autowired注入
单独使用@Autowired注解时,默认是根据类型装配
- @Autowired注解可以标注在:构造方法上、方法上、形参上、属性上、注解上
- @Autowired注解的required属性,
- 属性值为True:表示注入的时候要求被注入的Bean必须是存在的,如果不存在则报错
- 属性值为False::表示注入的时候要求被注入的Bean不一定是存在的,如果存在的话就注入,不存在的话,也不报错
1.4.1、属性注入
当使用@Autowired注解注入时,可不提供构造方法喝Setter方法,也可以注入成功
1.创建UserDao接口
package com.atguigu.spring6.dao;
public interface UserDao {
public void print();
}
2.创建UserDaoImpl实现
package com.atguigu.spring6.dao.impl;
import com.atguigu.spring6.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void print() {
System.out.println("Dao层执行结束");
}
}
3.创建UserService接口
package com.atguigu.spring6.service;
public interface UserService {
public void out();
}
4.创建UserServiceImpl实现类
package com.atguigu.spring6.service.impl;
import com.atguigu.spring6.dao.UserDao;
import com.atguigu.spring6.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
//注入dao
//属性注入
@Autowired//根据类型找到对应对象,完成注入
private UserDao userDao;
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
5.创建UserController类
package com.atguigu.spring6.controller;
import com.atguigu.spring6.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
//注入service
//属性注入
@Autowired//根据类型找到对应对象,完成注入
private UserService userService;
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
步骤二:演示
@Test
public void testAnnotation(){
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.out();
}
1.4.2、set注入
1.修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowired//set方法注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
2.修改UserController类
@Controller
public class UserController {
private UserService userService;
@Autowired//set方法注入
public void setUserService(UserService userService) {
this.userService = userService;
}
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
1.4.3、构造方法注入
1.修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
2.修改UserController类
@Controller
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
1.4.4、形参注入
1.修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(@Autowired UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
2.修改UserController类
@Controller
public class UserController {
private UserService userService;
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
1.4.5、无注解注入
当有参数的构造方法只有一个时,@Autowired注解可以省略
1.修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
1.4.6、联合@Qualifier注解注入
当需要注入的接口有多个实现类时,可以联合使用@Qualifier(“userDaoImpl”) 注解,并指定实现类的名字,即可完成属性注入
1.添加UserDaoRedisImpl类
@Repository
public class UserDaoRedisImpl implements UserDao {
@Override
public void print() {
System.out.println("Redis Dao层执行结束");
}
}
说明:
- 此时,添加实现UserDao接口类,已经造成一个接口对应两个实现类
- 此时,程序错误,信息中说:不能装配,UserDao这个Bean的数量等于2
步骤二:修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDaoImpl") // 指定bean的名字
private UserDao userDao;
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
1.5、使用@Resource注入
@Resource注解是通过名称匹配的方式来实现注入的,默认按照名称进行匹配,未指定名称,使用属性名作为name,如果找不到匹配的名称,则会尝试按照类型匹配。
用在属性上、set方法上
如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
1.5.1、Name注入
1.修改UserDaoImpl类
package com.atguigu.spring6.dao.impl;
import com.atguigu.spring6.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository("myUserDao")
public class UserDaoImpl implements UserDao {
@Override
public void print() {
System.out.println("Dao层执行结束");
}
}
当使用注解时,在小括号内写上属性名称表示为此Bean定义别名
2.修改UserServiceImpl类
package com.atguigu.spring6.service.impl;
import com.atguigu.spring6.dao.UserDao;
import com.atguigu.spring6.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Resource(name = "myUserDao")
private UserDao myUserDao;
@Override
public void out() {
myUserDao.print();
System.out.println("Service层执行结束");
}
}
当使用@Resource注解时,可以使用name属性指定属性注入的别名
1.5.2、未知Name注入
1.修改UserDaoImpl类
package com.atguigu.spring6.dao.impl;
import com.atguigu.spring6.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository("myUserDao")
public class UserDaoImpl implements UserDao {
@Override
public void print() {
System.out.println("Dao层执行结束");
}
}
2.修改UserServiceImpl类
package com.atguigu.spring6.service.impl;
import com.atguigu.spring6.dao.UserDao;
import com.atguigu.spring6.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserDao myUserDao;
@Override
public void out() {
myUserDao.print();
System.out.println("Service层执行结束");
}
}
当使用@Resource注解时,在name属性未知的情况下,将属性注入的成员属性变量名定义为与Bean同名,即可完成注入
1.5.3、类型注入
1.原UserDaoImpl类
@Repository("myUserDao")
public class UserDaoImpl implements UserDao {
@Override
public void print() {
System.out.println("Dao层执行结束");
}
}
2.修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserDao userDao1;
@Override
public void out() {
userDao1.print();
System.out.println("Service层执行结束");
}
}
当使用@Resource注解时,现在userDao1属性名不存在,但仍然可以注入成功。因为,UserDao他们的类型名相同
1.6、全注解开发
全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件
使用@ComponentScan注解,进行组件扫描,从而替代了原有在xml文件中的配置
步骤一:创建配置类
@Configuration
//@ComponentScan({"com.atguigu.spring6.controller", "com.atguigu.spring6.service","com.atguigu.spring6.dao"})
@ComponentScan("com.atguigu.spring6")
public class Spring6Config {
}
步骤二:演示
需要使用AnnotationConfigApplicationContext类来获取Spring6Config的字节码文件
@Test
public void testAllAnnotation(){
ApplicationContext context = new AnnotationConfigApplicationContext(Spring6Config.class);
UserController userController = context.getBean("userController", UserController.class);
userController.out();
logger.info("执行成功");
}