【面试必问】Spring核心之控制反转(IOC)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Spring Bean是Spring框架中的一个核心概念,它是一个由Spring容器管理的对象。在Spring中,Bean是指任何一个由Spring容器所管理的对象,可以是Java类的实例、数据源、事务管理器等等

tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。

💕💕 推荐:体系化学习Java(Java面试专题)

1686493841110.jpg

1、如何理解 IOC

1.1、什么是 Spring Bean

Spring Bean是Spring框架中的一个核心概念,它是一个由Spring容器管理的对象。在Spring中,Bean是指任何一个由Spring容器所管理的对象,可以是Java类的实例、数据源、事务管理器等等。
Spring Bean的创建、初始化、销毁等生命周期都由Spring容器控制,这样可以将应用程序的对象解耦合,提高模块化和可重用性。Spring Bean可以通过注解、XML配置文件等方式进行声明和配置,Spring容器会根据配置信息创建对应的Bean对象并将其注入到需要使用的地方。

在使用Spring框架时,Bean是非常重要的概念,理解和掌握Bean的创建和管理方式对于开发高质量的Spring应用程序非常重要。

public class HelloWorld {
   
   
    private String message;
     public void setMessage(String message) {
   
   
        this.message = message;
    }
     public void getMessage() {
   
   
        System.out.println("Your Message : " + message);
    }
}

然后,在Spring的配置文件中声明该Bean:

<bean id="helloWorld" class="com.example.HelloWorld">
    <property name="message" value="Hello World!"/>
</bean>

上述配置文件中,id属性指定了Bean的唯一标识符,class属性指定了Bean的类型,property元素用于设置Bean的属性。

最后,在Java代码中使用该Bean

public static void main(String[] args) {
   
   
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
    obj.getMessage();
}

以上就是一个Bean的创建和使用。

1.2、Spring Bean 是单例的吗?

默认情况下,Spring Bean 是单例的,也就是说,Spring 容器只会创建一个 Bean 实例,并在需要时返回该实例。这是因为单例模式可以提高系统性能,避免了频繁创建和销毁对象的开销。

如果需要创建多个实例,可以通过在配置文件中设置 scope 属性来实现。例如,将 scope 属性设置为“prototype”表示该 Bean 的实例是多例的,每次请求都会创建一个新的实例。

需要注意的是,如果一个 Bean 是单例的,那么在多线程环境下访问时可能会存在线程安全问题。因此,在编写 Bean 的代码时需要注意线程安全问题,或者通过设置 scope 属性为“prototype”来避免线程安全问题,如下:

@Service
@Scope("prototype")
public class UserService {
   
   
    // ...
}

1.3、什么是 IOC

IOC(Inversion of Control,控制反转)是一种设计模式,它将对象之间的依赖关系的控制权从程序代码中转移到了容器中,通过容器来实现对象的创建、销毁、管理和依赖注入等操作,从而降低了代码的耦合度,提高了代码的可维护性和可扩展性。

在传统的编程模式中,对象之间的依赖关系是在程序代码中直接实现的,这样会导致代码的耦合度很高,难以维护和扩展。而采用IOC模式,将对象之间的依赖关系的控制权交给容器来管理,程序代码只需要定义好依赖关系,容器就可以自动地完成对象的创建、销毁、管理和依赖注入等操作,从而降低了代码的耦合度,提高了代码的可维护性和可扩展性。

在Java开发中,Spring框架就是一个典型的IOC容器,它通过XML配置文件或注解的方式来管理对象之间的依赖关系,实现了对象的创建、销毁、管理和依赖注入等操作。

1.4、IOC 的好处

IOC模式的主要作用是降低程序代码的耦合度,提高代码的可维护性和可扩展性。具体来说,IOC模式可以带来以下几个方面的好处:

  1. 降低代码的耦合度:将对象之间的依赖关系的控制权交给容器来管理,程序代码只需要定义好依赖关系,不需要关心对象的创建、销毁、管理和依赖注入等操作,从而降低了代码之间的耦合度。
  2. 提高代码的可维护性:采用IOC模式,可以使程序代码更加清晰、简洁,易于理解和维护。
  3. 提高代码的可扩展性:采用IOC模式,可以方便地添加、修改、替换对象之间的依赖关系,从而实现代码的可扩展性。
  4. 提高代码的测试性:采用IOC模式,可以方便地进行单元测试和集成测试,从而提高代码的测试性。
  5. 降低代码的重复性:采用IOC模式,可以避免在程序代码中重复创建对象,从而降低了代码的重复性。

总之,采用IOC模式可以使程序代码更加灵活、易于维护和扩展,是现代软件开发中的一种重要的设计模式。

1.4、什么是 DI

DI是Dependency Injection(依赖注入)的缩写,是一种设计模式,也是面向对象编程中的一个重要概念。DI的主要作用是降低程序代码的耦合度,提高代码的可维护性和可扩展性。

依赖注入是指在创建对象时,将对象所依赖的其他对象的引用作为参数传递给对象的构造函数或者其他方法中,从而实现对象之间的依赖关系。这样,对象之间的依赖关系就不再由程序代码直接控制,而是由容器来管理。这样可以使程序代码更加灵活、易于维护和扩展。

依赖注入有三种方式:构造函数注入、属性注入和方法注入。其中,构造函数注入是最常用的一种方式,也是最推荐的一种方式。在构造函数注入中,依赖关系是在对象创建时就确定的,这样可以保证对象的依赖关系在整个生命周期中都是稳定的,从而提高代码的可维护性和可测试性。

依赖注入是现代软件开发中的一个重要概念,采用依赖注入可以使程序代码更加灵活、易于维护和扩展,是面向对象编程中的一种重要的设计模式。

总而言之,IOC 是设计思想,而 DI 是设计实现

2、IOC 的三种配置方式

IOC(Inversion of Control,控制反转)是一种设计模式,通过将对象的创建和依赖关系的管理交给容器来实现,从而降低程序代码的耦合度,提高代码的可维护性和可扩展性。IOC 的三种配置方式包括 XML 配置、注解配置和 Java 配置,下面分别用代码说明:

1. XML 配置方式:

假设我们有一个 UserService 接口和一个 UserServiceImpl 实现类,其中 UserServiceImpl 依赖于 UserDao 接口和 RedisTemplate 对象。我们可以通过 XML 配置文件来管理它们的依赖关系,示例代码如下:

UserService 接口:

public interface UserService {
   
   
    void save(User user);
}

UserServiceImpl 实现类:

public class UserServiceImpl implements UserService {
   
   
     private UserDao userDao;
    private RedisTemplate redisTemplate;
     public void setUserDao(UserDao userDao) {
   
   
        this.userDao = userDao;
    }
     public void setRedisTemplate(RedisTemplate redisTemplate) {
   
   
        this.redisTemplate = redisTemplate;
    }
     @Override
    public void save(User user) {
   
   
        userDao.save(user);
        redisTemplate.opsForValue().set(user.getId(), user);
    }
}

XML 配置文件:

<bean id="userService" class="com.example.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
    <property name="redisTemplate" ref="redisTemplate"/>
</bean>

<bean id="userDao" class="com.example.UserDaoImpl"/>
 <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="localhost"/>
    <property name="port" value="6379"/>
</bean>

2. 注解配置方式:
我们可以通过注解来管理对象的依赖关系,示例代码如下:

UserServiceImpl 实现类:

@Service
public class UserServiceImpl implements UserService {
   
   
     @Autowired
    private UserDao userDao;
     @Autowired
    private RedisTemplate redisTemplate;
     @Override
    public void save(User user) {
   
   
        userDao.save(user);
        redisTemplate.opsForValue().set(user.getId(), user);
    }
}

UserDao 接口:

public interface UserDao {
   
   
    void save(User user);
}

UserDaoImpl 实现类:

@Repository
public class UserDaoImpl implements UserDao {
   
   
    @Override
    public void save(User user) {
   
   
        // save user
    }
}

RedisTemplate 对象的配置和 XML 配置方式相同。

3. Java 配置方式:

我们可以通过 Java 配置类来管理对象的依赖关系,示例代码如下:

UserServiceImpl 实现类:

@Service
public class UserServiceImpl implements UserService {
   
   
     private UserDao userDao;
    private RedisTemplate redisTemplate;
     @Autowired
    public UserServiceImpl(UserDao userDao, RedisTemplate redisTemplate) {
   
   
        this.userDao = userDao;
        this.redisTemplate = redisTemplate;
    }
     @Override
    public void save(User user) {
   
   
        userDao.save(user);
        redisTemplate.opsForValue().set(user.getId(), user);
    }
}

UserDao 接口和 UserDaoImpl 实现类同注解配置方式。

RedisTemplate 的配置通过 Java 配置类来实现:

@Configuration
public class AppConfig {
   
   
     @Bean
    public RedisTemplate redisTemplate() {
   
   
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }
     @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
   
   
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName("localhost");
        jedisConnectionFactory.setPort(6379);
        return jedisConnectionFactory;
    }
}

3、依赖注入的三种方式

依赖注入(Dependency Injection,DI)是一种实现控制反转(Inversion of Control,IoC)的设计模式,它通过将对象的依赖关系由调用者转移到外部容器中,以实现松耦合和可维护性。依赖注入一般分为三种方式:构造函数注入、Setter方法注入和接口注入。

下面是三种方式的代码举例:

1. 构造函数注入

public class UserServiceImpl implements UserService {
   
   
    private UserDao userDao;
     public UserServiceImpl(UserDao userDao) {
   
   
        this.userDao = userDao;
    }
     //...
}
 public class UserController {
   
   
    private UserService userService;
     public UserController(UserService userService) {
   
   
        this.userService = userService;
    }
     //...
}
 // 创建对象时进行依赖注入
UserDao userDao = new UserDaoImpl();
UserService userService = new UserServiceImpl(userDao);
UserController userController = new UserController(userService);

2. Setter方法注入

public class UserServiceImpl implements UserService {
   
   
    private UserDao userDao;
     public void setUserDao(UserDao userDao) {
   
   
        this.userDao = userDao;
    }
     //...
}
 public class UserController {
   
   
    private UserService userService;
     public void setUserService(UserService userService) {
   
   
        this.userService = userService;
    }
     //...
}
 // 创建对象后通过Setter方法进行依赖注入
UserDao userDao = new UserDaoImpl();
UserService userService = new UserServiceImpl();
userService.setUserDao(userDao);
UserController userController = new UserController();
userController.setUserService(userService);在这里插入代码片

3. 注解注入

public interface UserDao {
   
   
    //...
}

public class UserDaoImpl implements UserDao {
   
   
    //...
}

public interface UserService {
   
   
    //...
}

@Service
public class UserServiceImpl implements UserService {
   
   
    @Autowired
    private UserDao userDao;
     //...
}

4、IOC 源码剖析

Spring框架就是基于IoC思想实现的一个轻量级的容器,它可以帮助开发者管理对象之间的依赖关系,从而提高代码的可维护性和可扩展性。

下面我们来剖析Spring框架中IoC的实现原理:

1. IoC容器

Spring框架中的IoC容器是一个核心组件,它负责管理应用中的所有Bean对象。在Spring中,IoC容器分为两种类型:BeanFactory和ApplicationContext。

BeanFactory是IoC容器的基础接口,它提供了Bean的基本管理功能,如Bean的创建、销毁等。ApplicationContext是BeanFactory的子接口,它在BeanFactory的基础上增加了更多的功能,如国际化、事件处理等。

2. Bean的定义和注册

在Spring中,Bean的定义通过BeanDefinition来表示。BeanDefinition中包含了Bean的类名、属性等信息,它是IoC容器管理Bean的基础。

Bean的注册是通过BeanFactory或ApplicationContext来完成的。在注册Bean时,需要指定Bean的名称和对应的BeanDefinition。

下面是一个简单的BeanDefinition的代码示例:

GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(UserServiceImpl.class);
beanDefinition.getPropertyValues().add("userDao", new RuntimeBeanReference("userDao"));

在上面的代码中,我们创建了一个GenericBeanDefinition对象,并设置了Bean的类名和依赖关系。其中,RuntimeBeanReference表示对另一个Bean的引用。

3. Bean的实例化

在IoC容器启动时,会根据BeanDefinition创建对应的Bean实例。Bean的实例化是通过BeanFactory或ApplicationContext中的BeanFactoryPostProcessor和BeanPostProcessor来完成的。

BeanFactoryPostProcessor是在Bean实例化之前执行的,它可以修改BeanDefinition中的属性,或者添加新的BeanDefinition。BeanPostProcessor是在Bean实例化之后执行的,它可以对Bean进行后置处理,如初始化、销毁等。

下面是一个简单的BeanFactoryPostProcessor的代码示例:

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   
   
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   
   
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
        beanDefinition.getPropertyValues().add("userDao", new RuntimeBeanReference("userDao"));
    }
}

在上面的代码中,我们创建了一个MyBeanFactoryPostProcessor对象,并实现了postProcessBeanFactory方法。该方法会在Bean实例化之前被调用,我们可以在该方法中修改BeanDefinition中的属性。

4. Bean的依赖注入

在IoC容器启动时,会自动将Bean之间的依赖关系进行注入。依赖注入是通过BeanFactory或ApplicationContext中的AutowiredAnnotationBeanPostProcessor来完成的。

AutowiredAnnotationBeanPostProcessor是一个BeanPostProcessor,它会扫描所有的Bean,并自动注入它们之间的依赖关系。在注入依赖关系时,它会根据BeanDefinition中的属性进行匹配,并自动创建依赖对象。

下面是一个简单的依赖注入的代码示例:

@Service
public class UserServiceImpl implements UserService {
   
   
    @Autowired
    private UserDao userDao;
    //...
}

在上面的代码中,我们使用了@Autowired注解来标记依赖关系。在IoC容器启动时,会自动将UserDao对象注入到UserServiceImpl中。

这里只是大致讲了下,因为如果要展开细致将会非常长,有兴趣的可以看看我另一篇帖子,是一张图,比较细致的描绘了IOC 的创建Bean的过程,IOC详解

5、IOC 常见问题

5.1、为什么推荐构造器注入方式?

推荐使用构造器注入方式的原因主要有以下几点:

  1. 显式表达依赖关系:使用构造器注入方式可以明确地表达依赖关系,开发者可以清晰地知道哪些依赖是必须的,哪些是可选的。

  2. 可以保证依赖完整性:使用构造器注入方式可以保证依赖的完整性,即只有在所有必须的依赖都被注入后,才能创建对象。这样可以避免因为缺少依赖而导致的运行时异常。

  3. 更容易进行单元测试:使用构造器注入方式可以更容易进行单元测试,因为可以直接传入模拟的依赖对象,而不需要依赖于IoC容器。

  4. 可以避免循环依赖问题:使用构造器注入方式可以避免循环依赖问题,因为只有在所有必须的依赖都被注入后,才能创建对象,从而避免了循环依赖的情况。

使用构造器注入方式可以使依赖关系更加清晰明确,保证依赖完整性,更容易进行单元测试,并且避免循环依赖问题。

5.2、我在使用构造器注入方式时注入了太多的类导致Bad Smell怎么办?

如果在使用构造器注入方式时注入了太多的类,导致代码出现了Bad Smell,可以考虑使用依赖注入容器来管理依赖关系。依赖注入容器可以自动地创建对象并注入依赖,从而减少手动注入的工作量,同时也可以减少代码的耦合度,提高代码的可维护性和可测试性。

在使用依赖注入容器时,可以将需要注入的依赖关系配置在容器中,容器会自动创建对象并注入依赖。这样可以避免手动注入过多的类,从而减少代码的复杂度和维护成本。

同时,也可以考虑使用依赖倒置原则,将高层模块依赖于抽象接口,而不是具体实现。这样可以减少依赖关系的复杂度,提高代码的可扩展性和可维护性。

如果在使用构造器注入方式时注入了太多的类导致Bad Smell,可以考虑使用依赖注入容器来管理依赖关系,同时也可以使用依赖倒置原则来减少依赖关系的复杂度。

5.3、@Autowired和@Resource以及@Inject等注解注入有何区别?

@Autowired、@Resource和@Inject是三种常见的依赖注入注解,它们的作用都是将一个Bean注入到另一个Bean中。它们的区别如下:

1. @Autowired
@Autowired是Spring框架提供的注解,它可以自动装配一个Bean。它默认按照类型(class)进行匹配,如果找到多个匹配的Bean,则按照Bean的名称进行匹配。如果找不到匹配的Bean,则会抛出异常。@Autowired还支持通过required属性来控制是否必须注入,如果required为true,则必须注入成功,否则会抛出异常。

2. @Resource
@Resource是Java EE提供的注解,它也可以自动装配一个Bean。它默认按照名称进行匹配,如果找不到匹配的Bean,则会抛出异常。@Resource还支持通过name属性来指定Bean的名称,也支持通过type属性来指定Bean的类型。

3. @Inject
@Inject是JSR-330提供的注解,它也可以自动装配一个Bean。它默认按照类型(class)进行匹配,如果找到多个匹配的Bean,则会抛出异常。@Inject还支持通过@Named注解来指定Bean的名称,也支持通过@Qualifier注解来指定Bean的类型。

@Inject注解可以用来注入一个Bean到另一个Bean中。以下是一个使用@Inject注解的示例:

假设我们有一个UserService接口和一个UserServiceImpl实现类,我们需要在另一个类中使用UserService,可以通过@Inject注解来注入UserService实例,代码如下:

public class UserController {
   
   
    @Inject
    private UserService userService;
     public void getUserList() {
   
   
        List<User> userList = userService.getUserList();
        // do something with userList
    }
}

在上面的代码中,我们使用@Inject注解将UserService实例注入到UserController类中的userService属性中。这样,在getUserList()方法中就可以直接使用userService来调用UserService中的方法了。

需要注意的是,为了使用@Inject注解,需要在项目中引入javax.inject包,这个包通常是由Java EE容器提供的,如果使用Spring框架,可以通过在pom.xml文件中添加以下依赖来引入javax.inject包:

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

总的来说,@Autowired是Spring框架提供的注解,@Resource是Java EE提供的注解,@Inject是JSR-330提供的注解。它们的作用都是将一个Bean注入到另一个Bean中,区别在于匹配规则、支持的属性和异常处理方式等方面。在实际使用中,可以根据具体的需求和场景来选择使用哪种注解。
1686494501743.jpg

💕💕 本文由激流原创
💕💕喜欢的话记得点赞收藏啊

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
29天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
67 2
|
13天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
30 2
|
16天前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
1月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
37 0
|
2月前
|
设计模式 缓存 Java
面试题:谈谈Spring用到了哪些设计模式?
面试题:谈谈Spring用到了哪些设计模式?
|
2月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
76 0
|
XML JSON 前端开发
Spring 面试 7 大问题,你顶得住不?
Spring 面试 7 大问题,你顶得住不?
230 0
Spring 面试 7 大问题,你顶得住不?
|
XML Java 数据格式
Spring 面试问题 TOP 50
Spring Framework 现在几乎已成为 Java Web 开发的标配框架。那么,作为 Java 程序员,你对 Spring 的主要技术点又掌握了多少呢?不妨用本文的问题来检测一下。
1327 0
|
XML Java 数据格式
Spring面试基本问题(1)
1、什么是Spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。
1956 0