组件和组件的管理概念
组件就是可以复用的java对象
‘
核心容器理解
Spring IoC / DI 实现步骤
1,配置元数据(配置)
配置元数据,既是编写交给SpringIoC容器管理组件的信息,配置方式有三种。 基于 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." [1] class="..." [2]>
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
Spring IoC 容器管理一个或多个组件。这些 组件是使用你提供给容器的配置元数据(例如,以 XML <bean/>
定义的形式)创建的。
id
属性是标识单个 Bean 定义的字符串。class
属性定义 Bean 的类型并使用完全限定的类名。
2,实例化ioc容器
提供给 ApplicationContext 构造函数的位置路径是资源字符串地址,允许容器从各种外部资源(如本地文件系统、Java CLASSPATH 等)加载配置元数据。 我们应该选择一个合适的容器实现类,进行IoC容器的实例化工作:
//实例化ioc容器,读取外部配置文件,最终会在容器内进行ioc和di动作
ApplicationContext context =
new ClassPathXmlApplicationContext("services.xml", "daos.xml");
3,获取Bean组件
ApplicationContext 是一个高级工厂的接口,能够维护不同 bean 及其依赖项的注册表。通过使用方法 T getBean(String name, Class requiredType) ,您可以检索 bean 的实例。 允许读取 Bean 定义并访问它们,如以下示例所示:
//创建ioc容器对象,指定配置文件,ioc也开始实例组件对象
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
//获取ioc容器的组件对象
PetStoreService service = context.getBean("petStore", PetStoreService.class);
//使用组件对象
List<String> userList = service.getUsernameList();
基于xml的ioc的配置
pom.xml配置文件中引入依赖:
<dependencies>
<!--spring context依赖-->
<!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.6</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
并设置打包方式为pom方式:
<packaging>pom</packaging>
基于无参数构造函数
1,准备组件类
package com.atguigu.ioc;
public class HappyComponent {
//默认包含无参数构造函数
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
2,编写配置文件
<!-- 实验一 [重要]创建bean -->
<bean id="happyComponent" class="com.atguigu.ioc.HappyComponent"/>
- bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件信息
- id属性:bean的唯一标识,方便后期获取Bean!
- class属性:组件类的全限定符!
- 注意:要求当前组件类必须包含无参数构造函数!
基于静态工厂方法实例化
1,准备组件类:
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
xml文件:
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
- class属性:指定工厂类的全限定符!
- factory-method: 指定静态工厂方法,注意,该方法必须是static方法。(注意:必须是静态工厂才能用这个指定)
基于实例工厂方法实例化
1,准备组件类
public class DefaultServiceLocator {
private static ClientServiceImpl clientService = new ClientServiceImpl();
public ClientServiceImpl createClientServiceInstance() {
return clientService;
}
}
2,配置工厂类的组件信息:
<bean id="defaultServiceLocator" class="com.bubu.ioc_01.DefaultServiceLocator"></bean>
3,通过指定非静态工厂和方法名来配置生成ioc信息
<bean id="clientService2" factory-bean="defaultServiceLocator" factory-method="createClientServiceInstance"></bean>
- factory-bean属性:指定当前容器中工厂Bean 的名称。
- factory-method: 指定实例工厂方法名。注意,实例方法必须是非static的!
基于xml的id配置
1,准备组件类
public class UserDao {
}
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
2,编写配置类
<bean id="userDao" class="com.bubu.ioc_02.UserDao"/>
<bean id="userService" class="com.bubu.ioc_02.UserService">
<constructor-arg ref="userDao"/>
</bean>
constructor-arg:构造参数传值的di配置
value:直接属性值 String="name" int age = 18
ref:引用其他bean (bean的id值)
springioc容器是一个高级容器,内部会有缓存动作:1,先创建对象【ioc】 2,再进行属性赋值【di】,所以bean对象的书写顺序不分先后。
使用不同的方式进行依赖注入:
public class UserDao {
}
public class UserService {
private UserDao userDao;
private int age;
private String name;
public UserService(int age , String name ,UserDao userDao) {
this.userDao = userDao;
this.age = age;
this.name = name;
}
}
<bean id="userDao" class="com.bubu.ioc_02.UserDao"/>
<bean id="userService" class="com.bubu.ioc_02.UserService">
<constructor-arg ref="userDao"/>
</bean>
<bean id="userService1" class="com.bubu.ioc_02.UserService">
<constructor-arg value="18"/>
<constructor-arg value="二狗子"/>
<constructor-arg ref="userDao"/>
</bean>
<bean id="userService2" class="com.bubu.ioc_02.UserService">
<constructor-arg name="age" value="18"/>
<constructor-arg name="name" value="二狗子"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
<bean id="userSeervice3" class="com.bubu.ioc_02.UserService">
<constructor-arg index="0" value="18"/>
<constructor-arg index="1" value="name"/>
<constructor-arg index="2" ref="userDao"/>
</bean>
还有一种基于set方法的依赖注入方式:
组件类:
public Class MovieFinder{
}
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String movieName;
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
public void setMovieName(String movieName){
this.movieName = movieName;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
<bean id="SimpleMovieLister" class="com.bubu.ioc_02.SimpleMovieLister">
<property name="" value="" ref=""/>
<property name="movieFinder" ref="MovieFinder"/>
<property name="movieName" value="name"/>
</bean>
注意:
name:属性名=>setter方法的去set和首字母小写的值!用于调用set方法的名
ioc容器的bean获取三种方式
public void getBeanFromIoc() {
/*1,创建ioc容器对象*/
ApplicationContext context = new ClassPathXmlApplicationContext("spring-03.xml");
/*2,读取ioc容器的组件*/
/*方案一:直接根据beanId获取即可 放回类型是Object 需要强转*/
HappyComponent happyComponent = (HappyComponent)context.getBean("happyComponent");
/*方案二:根据beanId,同时指定bean的类型 Class*/
HappyComponent happyComponent1 = (HappyComponent)context.getBean("happyComponent", HappyComponent.class);
/*方案三:直接根据类型获取 注意:使用这种方法时,同一个类型,在ioc容器中只能有一个bean!如果ioc容器中存在多个bean,会出现不唯一异常(前两个方案无需考虑这一点)*/
HappyComponent happyComponent2 = context.getBean(HappyComponent.class);
}
注:ioc的配置一定是实现类,但是可以根据接口类型获取值!
public interface A {
public void doWork();
}
public class HappyComponent implements A{
//默认包含无参数构造函数
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
/*方案三:直接根据类型获取*/
A happyComponent2 = context.getBean(A.class);
happyComponent2.doWork();
三层架构组件管理和jdbctemplate使用
依赖引入:
<!-- 数据库驱动和连接池-->
<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>
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.6</version>
</dependency>
配置文件:
<?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="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
测试代码:
@Test
public void testForIoc() {
/*1,创建ioc容器*/
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-01.xml");
/*2,获取jdbcTemplate组件*/
JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean(JdbcTemplate.class);
/*3,进行数据库的crud动作*/
String sql = null;
//插入:
sql = "insert into students (id,name,gender,age,class) values(?,?,?,?,?)";
/*参数1:String sql 可以带占位符? ?只能代替值 不能代替关键字*/
/*参数2:Object...param传入占位符的值 顺序:从左开始对象*/
/*放回值:int 影响函数*/
int rows = jdbcTemplate.update(sql, 9,"二狗子", "男", 18, "三年二班");
System.out.println("rows=" + rows);
//查询
sql = "select * from students where id = ?";
/*参数1:sql语句 可以使用?*/
/*参数2:RowMapper 列名和属性名的映射器*/
Student student1 = jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
//rs 结果集
//rowNum 行数
//rs 结果集中获取的值 赋值给实体类对象即可
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
student.setGender(rs.getString("gender"));
return student;
}, 1);
System.out.println("student1=" + student1);
//查询所有学生的数据
sql = "select id,name,gender,age,class as classes from students";
/*BeanPropertyRowMapper:帮助我们自动映射列和属性值!要求列名和属性名一致!!不一致要起别名*/
List<Student> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Student>(Student.class));
System.out.println("query=" + query);
}
基于注解方式配置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">
<!-- 配置自动扫描的包 -->
<!-- 1.包要精准,提高性能!
2.会扫描指定的包和子包内容
3.多个包可以使用,分割 例如: com.atguigu.controller,com.atguigu.service等
-->
<context:component-scan base-package="com.atguigu.components"/>
</beans>
排除包:
<context:component-scan base-package="com.atguigu.components">
<!-- context:exclude-filter标签:指定排除规则 -->
<!-- type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除 -->
<!-- expression属性:指定排除规则的表达式,对于注解来说指定全类名即可 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
指定扫描包:
<?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.springframewor
Bean组件作用域和周期方法注解
public class BeanOne {
//周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
@PostConstruct //注解制指定初始化方法
public void init() {
// 初始化逻辑
}
}
public class BeanTwo {
@PreDestroy //注解指定销毁方法
public void cleanup() {
// 释放资源逻辑
}
}
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例 二选一
public class BeanOne {
//周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
@PostConstruct //注解制指定初始化方法
public void init() {
// 初始化逻辑
}
}
DI注解:jsr-250注解 Java提供的注解 为spring 提供了一个 @Resource
引入依赖:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
@Controller
public class JavaTestController {
@Resource(name="javaTestIpml")
public JavaTest javaTest;
public List<Integer> getJavaTests() {
List<Integer> list = new ArrayList<>();
list=javaTest.setList();
list.forEach(System.out::println);
return list;
}
}
相当于:
基本类型注解:@Value 标签的作用
@Component()
public class JavaBean {
@Value("${jdbc.username:no}")
private String username;
@Value("${jdbc.password:no}")
private String password;
public void print() {
System.out.println(username+" and "+password);
}
}
@Test
public void testSpringIoc() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-02.xml");
com.bubu.ioc_02.JavaBean bean = context.getBean(com.bubu.ioc_02.JavaBean.class);
bean.print();
System.out.println(bean);
}
如果没有传进来值,默认值为“:”后面的值
ioc三层架构标签的使用
非三层架构建议使用Component
配置文件:
完全注解的使用
//标注当前类是配置类,替代application.xml
@Configuration
//引入jdbc.properties文件
@PropertySource({"classpath:application.properties","classpath:jdbc.properties"})
@ComponentScan(basePackages = {"com.atguigu.components"})
public class MyConfiguration {
//如果第三方类进行IoC管理,无法直接使用@Component相关注解
//解决方案: xml方式可以使用<bean标签
//解决方案: 配置类方式,可以使用方法返回值+@Bean注解
@Bean
public 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;
}
}
// AnnotationConfigApplicationContext-IOC容器对象
ApplicationContext iocContainerAnnotation =
new AnnotationConfigApplicationContext();
//外部设置配置类
iocContainerAnnotation.register(MyConfiguration.class);
//刷新后方可生效!!
iocContainerAnnotation.refresh();