Spring Framework 是一个开源的基于 Java 平台的应用程序开发框架。它提供了一个综合性的编程和配置模型,用于构建企业级的 Java 应用程序。
Spring Framework 的设计宗旨是通过依赖注入(Dependency Injection)和面向切面编程(Aspect-Oriented Programming)等技术降低企业应用程序的复杂性,并提供了一套全面的解决方案。
Spring Framework 的核心功能包括:
1. 控制反转(Inversion of Control,IoC):通过依赖注入的方式,将对象之间的依赖关系由编码实现转变为配置实现,通过配置文件或注解的方式将对象的依赖关系注入到容器中。
2. 面向切面编程(Aspect-Oriented Programming,AOP):提供了一种非侵入式的编程方式,通过切面对横切关注点(如事务管理、日志记录等)进行模块化和管理。
3. 数据访问与集成(Data Access and Integration):提供了对不同数据访问技术的支持,包括 JDBC、ORM 框架(如 Hibernate、MyBatis)、NoSQL 数据库等。
4. Web 开发支持:提供了对 Servlet、MVC 框架、RESTful Web 服务等的支持,简化了 Web 应用的开发和部署。
5. 安全性:提供了对身份验证、授权等安全方面的支持,保护应用程序的安全性。
Spring Framework 还有很多其他的功能模块,如消息队列、缓存、定时任务等,它们可以灵活地组合和使用,根据应用程序的需求进行定制。
总的来说,Spring Framework 提供了一种简化的开发模式和一整套解决方案,帮助开发者构建可测试、可维护、可扩展的企业级 Java 应用程序。它已经成为 Java 开发领域最受欢迎和广泛应用的框架之一。
企业的使用率达到的 90%,基本上现在的企业级项目都在用 spring 框架进行开发了,如果这还不够体现出 spring 的重要的话,大家可以去招聘网站去看 Java 后端开发的招聘要求,绝对都是需要会 spring 的。有句话说,不会 spring 就等于不会 Java。
总而言之,学习Spring框架可以帮助开发人员提高开发效率、降低代码复杂度、实现松耦合的设计,并且能够应用于各种Java应用程序的开发中。这使得Spring成为了Java开发领域一个非常重要的框架。
这门课程很重要,这是学习 spring 全家桶的基础,如果要学习其他的 spring 框架必须要学好这门课程。
这是我们以前写代码的方式,从图片中看,我们在业务层需要对 dao 实现类进行业务处理时,我们需要 New 一个 dao 接口的实现类出来。但是,现在 dao 接口有两个实现类,我们 New 一个对象已经不能满足我们了,当 dao 接口有多个实现类时,我们需要去 New 多个对象出来,就需要在业务层中去改动代码,每当 dao 接口有新的实现类,业务层就需要改一次代码,新 New 一个对象出来。
所以现在写代码的问题就是:耦合度太高了。
我们这样一改是不是就不会依赖 dao 层具体的实现了,直接就定一个 dao 变量,不就可以调用方法了吗?不就可以运行起来了吗?答案是不可以,虽然说编译没有错误,但是运行之后就会报空指针异常。
因为 userDao 只是一个空的变量,并没有给它赋值,所以运行会报空指针异常。所以现在问题就是,我们现在需要这个对象,但是我们不能在业务层 New 出一个对象,怎么办呢?
这就是本章节要讲的内容 Spring 容器和 bean 的装配。
使用对象的时候,在程序中不再主动使用 New 产生对象,将 New 对象交给外部(spring容器)去做。
org.springframework
spring-context
5.3.23
ch.qos.logback
logback-classic
1.4.5
导入之后会有五个包
Spring Framework是一个基于Java语言的开源应用框架,其核心部分由5个关键的模块组成:
spring-core.jar:Spring的核心容器,包含了IoC和DI的基本实现。
spring-context.jar:该模块建立在spring-core之上,提供Spring的整合上下文功能,包括对JNDI、EJB、邮件服务、调度任务等的支持。
spring-aop.jar:该模块提供了面向切面编程的特性,允许在程序运行期间动态地将代码横向插入到实现中。
spring-web.jar:该模块提供了一种方便的集成方式,使得Spring能够与Web应用程序进行更加紧密的集成。
spring-webmvc.jar:该模块提供了基于MVC模式的Web应用程序开发框架,通过提供一组可重用的MVC组件,使得开发人员可以轻松构建灵活的Web应用程序。
这五个核心模块可以根据需要进行逐一导入,并且它们也会默认导入其他必需的依赖项。当然,Spring Framework提供了非常丰富的扩展模块和第三方库,用户可以根据自己的需求选择性的导入相关的jar包。
public interface UserService {
void say();
}
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public void say() {
log.info("Hello spring...");
}
}
注意:接口本身不能被实例化,因为接口是一个抽象的概念,无法直接创建对象。因此,你不能将接口本身作为bean进行配置和装配。但是,可以将接口的实现类作为bean进行配置和装配。Spring提倡面向接口编程,因此通常我们会定义接口,并在实际的业务类中实现该接口。然后,可以通过配置文件或者注解来将实现类注册为bean,并通过接口类型来引用和使用这些实现类的实例。
这里要注意了,bean对象不能是接口和抽象类,所以这里的 class 指定的就是 UserServiceImpl 实现类的完整类名。 还有 bean 的 id 在同一个配置文件中是不能重复的。
public class Main {
public static void main(String[] args) {
// 创建容器工厂,(在 spring 框架中存在多种不同的容器工厂,每种容器工厂都有自身的特点和功能,例如:
// 当我们需要通过解析 xml 配置文件来初始化一个容器工厂时,可以使用 ClassPathXmlApplicationContext
// 这个容器工厂),而这些工厂最终实现的都是 ApplicationContext 接口
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 从容器中根据 bean 的 id 获取 bean 的实例
UserService userService = (UserService) context.getBean("userService");
// getBean 方法第二个参数执行泛型类型,因此不需要强转
UserService userService1 = context.getBean("userService", UserService.class);
// 如果接口的实现类只有一个,可以不需要指定 id,只需要泛型类型即可
UserService bean = context.getBean(UserService.class);
userService.say();
userService1.say();
bean.say();
}
}
这是获取 bean实例的三种方法,需要注意的是第三种,我们现在是只有一个实现类,当我们有两个及以上的实现类时,第三种方法就不可以使用了。
运行之后是不是三种方式都可以调用到我们的 say 方法输出, 这三种方法大家自己选择使用。
public class PeopleServiceImpl implements UserService {
@Override
public void say() {
System.out.println("Hello people");
}
}
public class PeopleServiceFactory {
/**
* 简单工厂,用来创建 PeopleServiceImpl 实例
* @return
*/
public UserService create(){
return new PeopleServiceImpl();
}
}
自定义工厂,并交给 spring 容器管理。第一种方法是把实现类交给容器管理,这种方法是创建一个简单工厂,这个工厂就负责创建具体的实现类的实例,然后再把这个工厂交给 spring 容器管理,是不是感觉和第一个一样呢。
// 创建容器工厂,(在 spring 框架中存在多种不同的容器工厂,每种容器工厂都有自身的特点和功能,例如:
// 当我们需要通过解析 xml 配置文件来初始化一个容器工厂时,可以使用 ClassPathXmlApplicationContext
// 这个容器工厂),而这些工厂最终实现的都是 ApplicationContext 接口
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 使用自定义工厂创建实例
UserService peopleService = (UserService) context.getBean("peopleService");
peopleService.say();
运行结果
public class StudentServiceImpl implements UserService {
@Override
public void say() {
System.out.println("Hello student");
}
}
public class StudentServiceFactoryBean implements FactoryBean {
/**
* 创建具体的 Bean 实例
* @return
* @throws Exception
*/
@Override
public UserService getObject() throws Exception {
return new StudentServiceImpl();
}
/**
* 返回 Bean 实例的 class 类型
* @return
*/
@Override
public Class> getObjectType() {
return StudentServiceImpl.class;
}
}
getObject():该方法返回所创建的 Bean 实例,这是工厂模式的核心方法。
getObjectType():该方法返回创建的对象的类型。
isSingleton():该方法返回 Bean 是否为单例。
这里没有实现 isSingleton() 方法,因为默认就是单例的。
// 创建容器工厂,(在 spring 框架中存在多种不同的容器工厂,每种容器工厂都有自身的特点和功能,例如:
// 当我们需要通过解析 xml 配置文件来初始化一个容器工厂时,可以使用 ClassPathXmlApplicationContext
// 这个容器工厂),而这些工厂最终实现的都是 ApplicationContext 接口
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 实现 FactoryBean 接口创建 Bean 对象
UserService studentService = (UserService) context.getBean("studentService");
studentService.say();
运行结果
使用实现了 FactoryBean 接口的自定义工厂有以下好处:
1、灵活性:通过自定义工厂,你可以在创建 Bean 实例之前进行一些自定义逻辑,例如初始化、参数设置等。这样可以提供更大的灵活性来满足特定的需求。
2、隔离性:通过自定义工厂,你可以将一些复杂的实例化逻辑封装在工厂中,从而将其与业务逻辑相分离。这样可以提高代码的可维护性和可读性。
3、控制对象的生命周期:通过自定义工厂,你可以控制所创建的对象的生命周期。例如,可以设置为单例或原型模式,根据需要创建多个对象实例或共享单个对象实例。
4、延迟加载:当你的 Bean 对象很重量级或需要完成一些初始化操作时,你可以通过自定义工厂来延迟加载这些对象。只有当首次访问该对象时才会创建,从而提高应用程序的性能。
5、提供更高层次的抽象:通过自定义工厂,你可以提供一种更高层次的抽象,将复杂的创建过程封装在简单的接口后面。这样可以降低代码耦合度,提高代码的可扩展性和可复用性。
综上所述,使用实现了 FactoryBean 接口的自定义工厂可以为你的应用程序提供更大的灵活性、可控性和可维护性。
第一个入门案例就完成啦,大家是不是发现还是存在 New 一个对象出来的操作,代码之间的耦合度还是挺高的,该怎么解决呢?在后面的 DI:依赖注入中解决。
案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git