依赖:
classA 类中含有 classB 的实例,在 classA 中调用 classB 的方法完成功能,即 classA对 classB 有依赖。
Ioc 的实现:
依赖注入:DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。
依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持对象之间依赖关系的管理。
Spring 框架使用依赖注入(DI)实现 IoC。
Spring 容器是一个超级大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。
Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。
使用 IoC 实现对象之间的解耦和。
开发工具: idea2020.1
依赖管理: maven3.6.3
jdk: 1.8及以上
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SEFAVCp8-1658153514964)(../../../../Pictures/Spring/wps230.png)]](https://1000bd.com/contentImg/2022/07/21/155502761.png)
实现步骤如下:
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.5.RELEASEversion>
dependency>
dependencies>
public class Student {
private String name;
private int age;
//无参构造方法是为spring提供创建对象
public Student() {
System.**out**.println("我是学生类的无参构造方法");
}
//setXXX方法是为spring提供进行赋值操作的
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在 src/main/resources/目录现创建一个xml 文件,文件名可以随意,但 Spring 建议的名称为 applicationContext.xml。
spring 配置中需要加入约束文件才能正常使用,约束文件是 xsd 扩展名。
:用于定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
class:指定该Bean所属的类,注意这里只能是类,不能是接口。
spring 配置文件加入 java.util.Date 定义:
<bean id="myDate" class="java.util.Date" />
MyTest 测试类中:
调用 getBean(“myDate”); 获取日期类对象。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IQq8IqcJ-1658153514965)(../../../../Pictures/Spring/wps234.png)]](https://1000bd.com/contentImg/2022/07/21/155503714.png)
ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现类有两个。
若 Spring 配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现类进行加载。
ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。Spring初始化对象时要使用无参的构造方法,切记保证类中有无参构造方法。
测试类:
还可以创建系统类的对象并赋值。
对于其它 Bean 对象的引用,使用标签的 ref 属性。
测试方法:
constructor-arg:通过构造函数注入
property:通过setxx方法注入。
标签中用于指定参数的属性有:
//提供有参的构造方法为进行注入值
public Student(String myname, int myage) {
this.name = myname;
this.age = myage;
}
public Student(String name, int age, School school) {
this.name = name;
this.age = age;
this.school = school;
}
applicationContext.xml文件中:
<bean id="school" class="com.bjpowernode.pojo.s03.School">
<constructor-arg name="name" value="清华大学">constructor-arg>
<constructor-arg name="address" value="北京海淀区">constructor-arg>
bean>
<bean id="stu" class="com.bjpowernode.pojo.s03.Student">
<constructor-arg name="age" value="22">constructor-arg>
<constructor-arg name="name" value="张三">constructor-arg>
<constructor-arg name="school" ref="school">constructor-arg>
bean>
测试类:
<bean id="stuindex" class="com.bjpowernode.pojo.s03.Student">
<constructor-arg index="1" value="22">constructor-arg>
<constructor-arg index="0" value="李四">constructor-arg>
<constructor-arg index="2" ref="school">constructor-arg>
bean>
<bean id="stuno" class="com.bjpowernode.pojo.s03.Student">
<constructor-arg value="李四">constructor-arg>
<constructor-arg value="22">constructor-arg>
<constructor-arg ref="school">constructor-arg>
bean>
注意:此种方式的注入一定要按类中构造方法的参数的顺序来进行注入。
根据自动注入判断标准的不同,可以分为两种:
配置文件中被调用者 bean 的 class 属性指定的类,
要与代码中调用者 bean 类的某引用类型属性类型同源。
什么是同源类型:
a.被注入的类型(Student中的school)与注入的类型是完全相同的类型
b.被注入的类型(Student中的school父)与注入的类型(子)是父子类
c.被注入的类型(Student中的school接口)与注入的类型(实现类)是接口和实现类的类型
注意:在有父子类的情况下,使用按类型注入,就意味着有多个可注入的对象.此时按照名称进行二次筛选,选中与被注入对象相同名称的对象进行注入.
但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
我们可以通过创建系统时间来验证Spring创建对象的默认单例模式.
<bean id="mydate" class="java.util.Date" scope="singleton"> ===>单例模式
bean>
可以设置为非单例的方式:
<bean id="mydate" class="java.util.Date" scope="prototype">===>非单例模式
bean>
测试代码:
@Test public void testSpringStudent()throws Exception{
//创建容器对象并启动.自动完成容器中所有对象的创建,默认调用无参的构造方法.
//如果没有提供无参的构造方法,则容器炸掉
ApplicationContext ac = new ClassPathXmlApplicationContext("s04/applicationContext.xml");
Date date1 = (Date) ac.getBean("mydate");
System.out.println("第一次取出的对象:"+date1);
System.out.println("********************");
Thread.sleep(3000);
Date date2 = (Date) ac.getBean("mydate");
System.out.println("第二次取出的对象:"+date2);
System.out.println(date1==date2);
}
运行结果:
案例:
使用三层架构完成用户数据的增加操作.由Spring容器负责对象的创建与依赖注入.
分析:
在分层开发中,Spring管理controller,service,dao各层的实现类对象的创建及依赖管理。
创建对象的思路分析:
项目结构:
使用三层架构进行用户的插入操作.界面层,业务逻辑层,数据访问层(模拟).
Spring会接管三层架构中哪些对象的创建?界面层的对象,业务逻辑层的对象,数据访问层的对象.
非Spring接管下的三层项目构建:
代码实现:
指定多个包的三种方式:
分隔符可以使用逗号(,)或分号(;),还可以使用空格,不建议使用空格。
使用逗号分隔:
使用分号分隔:
base-package 的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。
或者最顶级的父包
但不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。指定到目标包和合适的。也就是注解所在包全路径。例如注解的类在 com.bjpowernode.beans 包中。
需要在类上使用注解@Component,该注解的 value 属性用于指定该 bean 的 id 值。
需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值。
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。
@Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运行。
若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。
注意:如果可注入的类型多于一个,则按名称进行二次匹配.如果有匹配到则注入,如果没有匹配到,则报错。
如果可注入的类型多于一个,则按名称进行匹配.如果有匹配到则注入,如果没有匹配到,则报错。
总结:
依赖注入的注解
简单类型(8种基本类型+String)的注入
@Value:用来给简单类型注入值引用类型的注入
@Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入.
同源类型也可注入.
什么是同源类型:
a.被注入的类型(Student中的school)与注入的类型是完全相同的类型
b.被注入的类型(Student中的school父)与注入的类型(子)是父子类
c.被注入的类型(Student中的school接口)与注入的类型(实现类)是接口和实现类的类型注意:在有父子类的情况下,使用按类型注入,就意味着有多个可注入的对象.此时按照名称进行二次筛选,选中与被注入对象相同名称的对象进行注入.
@Autowired
@Qualifier(“名称”):使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入.注意:如果有父子类的情况下,直接按名称进行注入值.
在每个类上添加创建对象的注解@Controller,@Service,@Repository,
每个需要依赖注入的成员变量使用按类型@Autowired依赖注入即可.
UsersMapperImpl.java
@Repository
public class UsersMapperImpl implements UsersMapper {
@Override
public int insert(Users users) {
System.out.println(users.getName()+"增加成功!");
return 1;
}
}
UsersServiceImpl.java
@Service
public class UsersServiceImpl implements UsersService {
//切记切记:一定会有数据访问层的对象,调用它完成底层数据库的操作
@Autowired
UsersMapper usersMapper;//= new UsersMapperImpl();
@Override
public int insert(Users u) {
return usersMapper.insert(u);
}
}
UsersController.java
@Controller
public class UsersController {
//切记切记:一定会有业务逻辑层的对象,指向实现类
@Autowired
UsersService usersService;// = new UsersServiceImpl();
//完成控制器中的增加用户的方法
public int insert(Users users){
return usersService.insert(users);
}
}
@Resource 注解若不带任何参数,采用默认按名称的方式注入,按名称不能注入 bean, 则会按照类型进行 Bean 的匹配注入。
@Resource 注解指定其 name 属性,则 name 的值即为按照名称进行匹配的 Bean 的 id。
注解优点:
注解弊端:
XML 方式优点:
XML 方式缺点:
在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将
Spring 配置文件分解成多个配置文件。
常见的拆分策略有按模块拆分和按层拆分,当然在实际工作中,会有更细的拆分方法。
可以使用通配符进行整合。但此时要求父配置文件名不能满足所能匹配的格式,否则将出现循环递归包含。就本例而言,父配置文件不能匹配 applicationContext-.xml 的格式,即不能起名为applicationContext-total.xml。
多个配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java
代码中只需要使用总配置文件对容器进行初始化即可。注意:可以使用通配符*进行批量整合。