昨天我们初步认识了Spring框架,了解其基本概念,还学习了IoC控制反转,它是Spring的基础,支撑着Spring对JavaBean的管理功能,JavaBean这就是简单工厂模式设计模式的经典实现。由Spring通过ApplicationContext帮我们创建对象,并且放在IoC容器中,等我们使用getBean方法从IoC容器中获取这个对象。以及Java中的反射机制,还有初步学习了依赖注入DI,那么今天就来深入学习一下控制反转IoC和依赖注入DI。
控制反转(Inversion of Control,缩写为IoC)是面向对象编程中的一个设计原则,用来降低程序代码之间的耦合度。
(1)在传统面向对象编程中:获取对象的方式是用new关键字主动创建一个对象,也就是说应用程序掌握着对象的控制权。
传统面向对象程序设计原则如图。
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传]
(2)IoC控制反转机制:指的是对象由Ioc容器统一管理,当程序需要使用对象时,可以直接从IoC容器中获取。这样对象的控制权就从应用程序转移到了IoC容器。
IoC设计原则如图,借助于IoC容器实现具有依赖关系对象之间的解耦,各个对象类封装之后,通过IoC容器来关联这些对象类。
依赖注入(Dependency Inject,缩写DI)就是由IoC容器在运行期间动态地将某种依赖资源注入对象之中。例如,将对象B注入(赋值)给对象A的成员变量。依赖注入的基本思想是:明确地定义组件接口,独立开发各个组件,然后根据组件的依赖关系组装运行。
依赖注入(DI)和控制反转(IoC)是从不同角度来描述了同一件事情。依赖注入是从应用程序的角度描述,即应用程序依赖IoC容器创建并注入它所需要的外部资源;而控制反转是从IoC容器的角度描述,即IoC容器控制应用程序,由IoC容器反向地向应用程序注入应用程序所需要的外部资源。这里所说的外部资源可以是外部实例对象,也可以是外部文件对象等。
依赖注入的作用就是在使用Spring框架创建对象时,动态的将其所依赖的对象注入到Bean组件中。
首先要了解一下:
元素
一个
元素表示构造方法的一个参数,且定义时不区分顺序,只需要通过
元素的name属性指定参数即可。
元素还提供了type属性类指定参数的类型,避免字符串和基本数据类型的混淆
①新建pojo包,包内编写用户类:User.java
package pojo;
public class User {
private int uid;//学生id
private String name;// 姓名
private int age;//年龄
private String info;//学生信息
//不写的话会默认生成无参构造器,若是写了有参构造器就不会自动生成无参的构造器,
// 那就得自己创建一个无参构造器,方便方法使用
//无参构造器
public User() {
}
//有参构造器
public User(int uid, String name, int age, String info) {
this.uid = uid;
this.name = name;
this.age = age;
this.info = info;
}
//getter和setter方法,这里不写,因为我们是使用构造器注入的方式
//重写toString()方法,便于遍历输入信息让我们观察结果
public String toString(){
return "学生id:"+this.uid+", 姓名:"+this.name+",年龄:"+this.age+", 学生信息:"+this.info;
}
}
这里千万记得要编写构造器
使用
元素,name指定属性,value指定属性的值
<bean id="user" class="pojo.User">
<constructor-arg name="uid" value="1">constructor-arg>
<constructor-arg name="age" value="13">constructor-arg>
<constructor-arg name="name" value="Stevedash">constructor-arg>
<constructor-arg name="info" value="世间无我这般人">constructor-arg>
bean>
这里的话,要记得写完所有的信息,因为我们构造器依赖注入根据的是有参构造器,若是构造器里面的参数列表,没有全部在bean中指定的话,或者指定参数错误,那么都会出现报错,如下图:
package Test;
import javafx.application.Application;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;
import static org.junit.jupiter.api.Assertions.*;
class UserTest {
//定义日志对象,用来日志输出
private Logger logger= Logger.getLogger(UserTest.class);
@Test
void UserTestByConstructor() {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
User user = context.getBean("user",User.class);
logger.info(user.toString());
}
}
输出结果:
这种依赖注入方式就是构造方法注入。
其实我们昨天就写过,属性setter方法注入了,现在再来一遍,就当复习加深一下
package pojo;
public class Password {
private String accountNumber;//账号名称
private String password;//密码
private String id;//消息记录的id
//getter和setter方法
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//重写toString()方法,便于遍历输入信息让我们观察结果
public String toString(){
return "记录id:"+this.id+", 账号名称:"+this.accountNumber+", 密码:"+this.password;
}
}
<bean id="password" class="pojo.Password">
<property name="id" value="1">property>
<property name="accountNumber" value="[email protected]">property>
<property name="password" value="11111111">property>
bean>
package Test;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Password;
import static org.junit.jupiter.api.Assertions.*;
class PasswordTest {
//定义日志对象,用来日志输出
private Logger logger= Logger.getLogger(PasswordTest.class);
@Test
void getId() {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
//属性setter方法注入
Password password=context.getBean("password",Password.class);
logger.info(password.toString());
}
}
输出结果如下:
下面的这种分层式是典型的软件开发中的分层和模块化设计
package dao;
public interface UserDao {
public boolean login(String name,String password);
}
这是在创建数据访问层(DAO层),用于处理与数据库的交互。在这一层,我们定义了一些接口,这些接口描述了对数据库的增、删、改、查等操作,比如这里的login()
方法是用来验证用户登录的。这样的设计分离了数据库访问逻辑与业务逻辑,方便修改和维护。
package dao;
public class UserDaoImpl implements UserDao {
@Override
public boolean login(String name, String password) {
if (name.equals("wgd")&&password.equals("stevedash")){
return true;
}
return false;
}
}
在这一步,我们为DAO接口创建了具体的实现类,这个实现类会实际地与数据库进行交互,执行具体的SQL查询和操作。这里的login()
方法的实现涉及从数据库中查询用户信息来验证登录。我们这里只做了简单的校验
package service;
public interface UserService {
public boolean login(String name,String password);
}
在这一步,我们在创建业务逻辑层(Service层)。Service层是用来封装业务逻辑的,将一些复杂的业务操作封装成更高层次的方法,这样其他地方调用时可以更简洁地处理业务逻辑。
package service.impl;
import dao.UserDao;
import service.UserService;
public class UserServiceImpl implements UserService {
UserDao userDao;
public void setUserDao(UserDao userDao)
{ this.userDao=userDao; }
@Override
public boolean login(String name, String password) {
return userDao.login(name,password);
}
}
我们为Service接口创建了具体的实现类。这个实现类会调用DAO层的方法,处理业务逻辑,并且对数据进行处理和转换。这里的login()
方法会调用DAO层的login()
方法来进行用户登录验证。
<bean id="userDao" class="dao.UserDaoImpl">bean>
<bean id="userService" class="service.impl.UserServiceImpl">
<property name="userDao" ref="userDao">property>
bean>
这一步是将上述创建的类交由Spring容器管理。Spring容器通过配置文件中的bean信息,知道了哪些类需要由它来创建和管理,然后可以通过依赖注入等方式将不同层的对象关联起来。
在spring-config.xml
中,我们配置了Service的实现类为UserService
,这使得我们可以在其他地方通过Spring容器获取这个Service对象,然后调用其中的方法,实现业务逻辑的处理。
package Test;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;
import static org.junit.jupiter.api.Assertions.*;
class UserDaoImplTest {
//定义日志对象,用来日志输出
private Logger logger= Logger.getLogger(UserDaoImplTest.class);
@Test
void login() {
// 加载applicationContext.xml配置
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("spring-config.xml");
UserService userService = (UserService)applicationContext.getBean("userService");// 获取配置中的UserService实例
boolean flag = userService.login("wgd", "stevedash");
if (flag) {
logger.info("登录成功");
} else {
logger.info("登录失败");
}
}
}
今天我们详细的讲解了控制反转IoC与依赖注入DI,包括控制反转的概念、IoC控制反转设计原则和传统面向对象设计原则的区别、什么是依赖注入、依赖注入的类型和依赖注入的应用。还粗略的讲解了一下,典型的软件开发中的分层和模块化设计,希望通过今天的学习,各位读者可以对Spring框架的基础有个大致的了解,为框架开发打下坚实基础。
想要跟着学习的可以去我的资源里面找对应的文件下载,我的md文件也会发上去,项目文件会上传可以自己跟着学习一下。
作者:Stevedash
发表于:2023年8月31日 16点56分