第二章 SpringFramework
四、SpringIoC 实践和应用
3. 基于 注解 方式管理 Bean
3.4 实验四:Bean 属性赋值:基本类型属性赋值(DI)
- @Value 通常用于注入外部化属性
3.4.1 声明外部配置
- application.properties
catalog.name=MovieCatalog
3.4.2 xml 引入外部配置
<!-- 引入外部配置文件-->
<context:property-placeholder location="application.properties" />
3.4.3 @Value 注解读取配置
package com.alex.components;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** projectName: com.alex.components** description: 普通的组件*/
@Component
public class CommonComponent {/*** 情况1: ${key} 取外部配置key对应的值!* 情况2: ${key:defaultValue} 没有key,可以给与默认值*/@Value("${catalog:hahaha}")private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
3.5 实验五:基于注解 + XML 方式整合三层架构组件
3.5.1 需求分析
- 搭建一个三层架构案例,模拟查询全部学生(学生表)信息,持久层使用 JdbcTemplate 和 Druid 技术,使用 XML+注解方式进行组件管理!
3.5.2 数据库准备
create database studb;use studb;CREATE TABLE students (id INT PRIMARY KEY,name VARCHAR(50) NOT NULL,gender VARCHAR(10) NOT NULL,age INT,class VARCHAR(50)
);INSERT INTO students (id, name, gender, age, class)
VALUES(1, '张三', '男', 20, '高中一班'),(2, '李四', '男', 19, '高中二班'),(3, '王五', '女', 18, '高中一班'),(4, '赵六', '女', 20, '高中三班'),(5, '刘七', '男', 19, '高中二班'),(6, '陈八', '女', 18, '高中一班'),(7, '杨九', '男', 20, '高中三班'),(8, '吴十', '男', 19, '高中二班');
3.5.3 项目准备
3.5.3.1 项目创建
- spring-annotation-practice-04
3.5.3.2 依赖导入
<dependencies><!--spring context依赖--><!--当你引入SpringContext依赖之后,表示将Spring的基础依赖引入了--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></dependency><!-- 数据库驱动和连接池--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version></dependency><!-- spring-jdbc --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.0.6</version></dependency></dependencies>
3.5.3.3 实体类准备
public class Student {private Integer id;private String name;private String gender;private Integer age;private String classes;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getClasses() {return classes;}public void setClasses(String classes) {this.classes = classes;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", gender='" + gender + '\'' +", age=" + age +", classes='" + classes + '\'' +'}';}
}
3.5.4 三层架构搭建和实现
3.5.4.1 持久层
//接口
public interface StudentDao {/*** 查询全部学生数据* @return*/List<Student> queryAll();
}//实现类
@Repository
public class StudentDaoImpl implements StudentDao {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 查询全部学生数据* @return*/@Overridepublic List<Student> queryAll() {String sql = "select id , name , age , gender , class as classes from students ;";/*query可以返回集合!BeanPropertyRowMapper就是封装好RowMapper的实现,要求属性名和列名相同即可*/List<Student> studentList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Student.class));return studentList;}
}
3.5.4.2 业务层
//接口
public interface StudentService {/*** 查询全部学员业务* @return*/List<Student> findAll();}//实现类
@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentDao studentDao;/*** 查询全部学员业务* @return*/@Overridepublic List<Student> findAll() {List<Student> studentList = studentDao.queryAll();return studentList;}
}
3.5.4.3 表述层
@Controller
public class StudentController {@Autowiredprivate StudentService studentService;public void findAll(){List<Student> studentList = studentService.findAll();System.out.println("studentList = " + studentList);}
}
3.5.5 三层架构 IoC 配置
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 导入外部属性文件 --><context:property-placeholder location="classpath:jdbc.properties" /><!-- 配置数据源 --><bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${alex.url}"/><property name="driverClassName" value="${alex.driver}"/><property name="username" value="${alex.username}"/><property name="password" value="${alex.password}"/></bean><bean class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="druidDataSource" /></bean><!-- 扫描Ioc/DI注解 --><context:component-scan base-package="com.alex.dao,com.alex.service,com.alex.controller" /></beans>
3.5.6 运行测试
public class ControllerTest {@Testpublic void testRun(){ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-ioc.xml");StudentController studentController = applicationContext.getBean(StudentController.class);studentController.findAll();}
}
3.5.7 注解+XML IoC 方式问题总结
- 自定义类可以使用注解方式,但是第三方依赖的类依然使用 XML 方式!
- XML 格式解析效率低!
4. 基于 配置类 方式管理 Bean
4.1 完全注解开发理解
- Spring 完全注解配置(Fully Annotation-based Configuration)是指通过 Java 配置类 代码来配置 Spring 应用程序,使用注解来替代原本在 XML 配置文件中的配置。相对于 XML 配置,完全注解配置具有更强的类型安全性和更好的可读性。
- 两种方式思维转化:
4.2 实验一:配置类和扫描注解
4.2.1 xml+注解方式
- 配置文件 application.xml
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置自动扫描的包 --><!-- 1.包要精准,提高性能!2.会扫描指定的包和子包内容3.多个包可以使用,分割 例如: com.alex.controller,com.alex.service等--><context:component-scan base-package="com.alex.components"/><!-- 引入外部配置文件--><context:property-placeholder location="application.properties" />
</beans>
- 测试创建 IoC 容器
// xml方式配置文件使用ClassPathXmlApplicationContext容器读取ApplicationContext applicationContext =new ClassPathXmlApplicationContext("application.xml");
4.2.2 配置类+注解方式(完全注解方式)
- 配置类
- 使用 @Configuration 注解将一个普通的类标记为 Spring 的配置类。
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;//标注当前类是配置类,替代application.xml
@Configuration
//使用注解读取外部配置,替代 <context:property-placeholder标签
@PropertySource("classpath:application.properties")
//使用@ComponentScan注解,可以配置扫描包,替代<context:component-scan标签
@ComponentScan(basePackages = {"com.alex.components"})
public class MyConfiguration {}
- 测试创建 IoC 容器
// AnnotationConfigApplicationContext 根据配置类创建 IOC 容器对象
ApplicationContext iocContainerAnnotation =
new AnnotationConfigApplicationContext(MyConfiguration.class);
- 可以使用 no-arg 构造函数实例化 AnnotationConfigApplicationContext ,然后使用 register() 方法对其进行配置。此方法在以编程方式生成 AnnotationConfigApplicationContext 时特别有用。以下示例演示如何执行此操作:
// AnnotationConfigApplicationContext-IOC容器对象
ApplicationContext iocContainerAnnotation =
new AnnotationConfigApplicationContext();
//外部设置配置类
iocContainerAnnotation.register(MyConfiguration.class);
//刷新后方可生效!!
iocContainerAnnotation.refresh();
4.2.3 总结
- @Configuration 指定一个类为配置类,可以添加配置注解,替代配置 xml 文件
- @ComponentScan(basePackages = {“包”,“包”}) 替代<context:component-scan 标签实现注解扫描
- @PropertySource(“classpath:配置文件地址”) 替代 <context:property-placeholder 标签
- 配合 IoC/DI 注解,可以进行完整注解开发!
4.3 实验二:@Bean 定义组件
-
场景需求:将 Druid 连接池对象存储到 IoC 容器
-
需求分析:第三方 jar 包的类,添加到 ioc 容器,无法使用@Component 等相关注解!因为源码 jar 包内容为只读模式!
4.3.1 xml 方式实现
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 引入外部属性文件 --><context:property-placeholder location="classpath:jdbc.properties"/><!-- 实验六 [重要]给bean的属性赋值:引入外部属性文件 --><bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"/><property name="driverClassName" value="${jdbc.driver}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></bean></beans>
4.3.2 配置类方式实现
- @Bean 注释用于指示方法实例化、配置和初始化要由 Spring IoC 容器管理的新对象。对于那些熟悉 Spring 的 <beans/> XML 配置的人来说, @Bean 注释与 <bean/> 元素起着相同的作用。
//标注当前类是配置类,替代application.xml
@Configuration
//引入jdbc.properties文件
@PropertySource({"classpath:application.properties","classpath:jdbc.properties"})
@ComponentScan(basePackages = {"com.alex.components"})
public class MyConfiguration {//如果第三方类进行IoC管理,无法直接使用@Component相关注解//解决方案: xml方式可以使用<bean标签//解决方案: 配置类方式,可以使用方法返回值+@Bean注解@Beanpublic DataSource createDataSource(@Value("${jdbc.user}") String username,@Value("${jdbc.password}")String password,@Value("${jdbc.url}")String url,@Value("${jdbc.driver}")String driverClassName){//使用Java代码实例化DruidDataSource dataSource = new DruidDataSource();dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);dataSource.setDriverClassName(driverClassName);//返回结果即可return dataSource;}
}