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

news2024/11/16 5:42:34

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

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

文章目录

  • 1、如何理解 IOC
    • 1.1、什么是 Spring Bean
    • 1.2、Spring Bean 是单例的吗?
    • 1.3、什么是 IOC
    • 1.4、IOC 的好处
    • 1.4、什么是 DI
  • 2、IOC 的三种配置方式
  • 3、依赖注入的三种方式
  • 4、IOC 源码剖析
  • 5、IOC 常见问题
    • 5.1、为什么推荐构造器注入方式?
    • 5.2、我在使用构造器注入方式时注入了太多的类导致Bad Smell怎么办?
    • 5.3、@Autowired和@Resource以及@Inject等注解注入有何区别?

在这里插入图片描述

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中,区别在于匹配规则、支持的属性和异常处理方式等方面。在实际使用中,可以根据具体的需求和场景来选择使用哪种注解。
在这里插入图片描述

💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/635004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

驱动开发:内核封装WFP防火墙入门

WFP框架是微软推出来替代TDIHOOK传输层驱动接口网络通信的方案&#xff0c;其默认被设计为分层结构&#xff0c;该框架分别提供了用户态与内核态相同的AIP函数&#xff0c;在两种模式下均可以开发防火墙产品&#xff0c;以下代码我实现了一个简单的驱动过滤防火墙。 WFP 框架分…

触发器和事件自动化的讲解

触发器和事件自动化 一、触发器 1、触发器的基本概念 触发器是和表相关的一种数据库对象&#xff0c;可以将他看作一种特殊的存储过程&#xff0c;不需要人为调动的存储过程。 关键字&#xff1a;trigger 基本作用&#xff1a;通过对表进行数据的插入、更新或删除等操作来触…

UnityVR--AudioManager--音频管理中心

目录 前言 建立音频配置文件AudioConfig 建立音频管理AudioManager 使用AudioManager播放音效 前言 关于音频组件的简单使用请详见VideoPlayer&AudioSource&#xff0c;不过在一个工程项目中&#xff0c;会有很多的声音文件&#xff0c;播放的时间和条件也不相同&#…

【算法题】2614. 对角线上的质数

题目&#xff1a; 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&#xff0c;返回 0 。 注意&#xff1a; 如果某个整数大于 1 &#xff0c;且不存在除 1 和自身之外的正整数因子&#xff0c;…

Docker环境下部署Ghost开源内容管理系统

Docker环境下部署Ghost开源内容管理系统 一、Ghost介绍1.1 Ghost简介1.2 Ghost特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Ghost镜像五、部署Ghost开源内容管理系统…

【linux工具备忘录】- tmux

文章目录 安装常用命令会话的进入和退出窗口创建、删除、切换窗口内的子窗口管理(创建/删除/切换)会话的后台托管管理 tmux的配置配置的创建配置重载修改前缀键更多使用说明 tmux的插件管理tpm插件管理器tmux-powerline 一个漂亮的底栏 安装 sudo apt install tmux常用命令 会…

分布式软件架构——RESTful服务

RESTful&#xff08;Representational State Transfer&#xff09; RESTful是一种网络应用程序的设计风格和开发方式&#xff0c;基于HTTP&#xff0c;可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景&#xff0c;实现第三方OTT调用移动网…

shell脚本基础2——条件语句、分支选择、循环语句

文章目录 一、条件语句二、分支选择三、循环语句3.1 for循环3.1.1 语法一3.1.2 语法二 3.2 while循环3.2.1 普通用法3.2.2 whileif判断循环3.2.3 特殊用法 3.3 until循环 四、break和continue4.1 break用法4.2 continue用法 五、自定义脚本退出状态码 一、条件语句 使用 if 语句…

XdsObjects .NET 8.45.1001.0 Crack

XdsObjects 是一个工具包&#xff0c;允许开发人员使用 IHE XDS 和 XDS-I 配置文件开发应用程序&#xff0c;只需花费最少的时间和精力&#xff0c;因为遵守配置文件和 ebXML 规则的所有艰苦工作都由该工具包处理。 它为所有角色提供客户端和服务器支持&#xff0c;包括&#…

【Spring MVC】学会这些你就会利用Spring Boot进行前后端交互了,美滋滋,距离编程世界更近一步了,何乐而不为呢 ? ? ?

前言: 大家好,我是良辰丫,! ! !&#x1f48c;&#x1f48c;&#x1f48c; &#x1f9d1;个人主页&#xff1a;良辰针不戳 &#x1f4d6;所属专栏&#xff1a;javaEE进阶篇之框架学习 &#x1f34e;励志语句&#xff1a;生活也许会让我们遍体鳞伤&#xff0c;但最终这些伤口会成…

【仪器使用操作笔记】 TDS1012示波器基础原理与使用

今日要学习使用的是一台实验室老旧战损版TDS1012示波器&#xff0c;它长这样&#xff1a; 本文会从以下目录的几个方面全方位介绍示波器的一些基础运用&#xff1a; 目录 一、面板按键旋钮介绍&#xff1a; 整体面板介绍&#xff1a; 示波器探头接线与校准接线&#xff1a; …

一文弄懂java中的代理模式

文章目录 简介静态代理动态代理Cglib代理spring中AOP使用代理总结 简介 代理(Proxy)模式是一种结构型设计模式&#xff0c;提供了对目标对象另外的访问方式&#xff1b;即通过代理对象访问目标对象。 这样做的好处是&#xff1a;可以在目标对象实现的基础上&#xff0c;增强额…

Atcoder Beginner Contest 305——D-F题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 305这场比赛的D-F题&#xff01; D题 题外话 安利一波自己的洛谷博客&#xff1a;点这里 思路 这道题还是比…

Hazel游戏引擎(010)预编译头

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言如何实现 前言 此节目的 由于项目中的头文件或者cpp文件都包含着c的头文件&#xff0c;有些重复&#xff0c;可以将它们包含的c头文件放在一个头文件内&#xff0c;这样不仅使代码简洁&#xff0c;而且预编译头可以…

算法刷题-哈希表-两个数组的交集

两个数组的交集 349. 两个数组的交集思路拓展后记其他语言版本相关题目 如果哈希值比较少、特别分散、跨度非常大&#xff0c;使用数组就造成空间的极大浪费&#xff01; 349. 两个数组的交集 力扣题目链接 题意&#xff1a;给定两个数组&#xff0c;编写一个函数来计算它们的…

Java集合框架:ArrayList详解

目录 一、ArrayList简介 二、ArrayList源码介绍&#xff08;动态扩容以及构造方法是如何实现的&#xff09; 1. 扩容机制&#xff1a; 源码&#xff1a; 源码详解&#xff1a; ​编辑 如何扩容&#xff1a; 2. 扩容源码详解&#xff1a; 三、ArrayList的构造方法 四、ArrayL…

【Linux运维】GitLab本地服务器搭建

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍gitlab本地服务器的搭建。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习知识&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新…

【JVM内存模型】—— 每天一点小知识

&#x1f4a7; J V M 内存模型 \color{#FF1493}{JVM内存模型} JVM内存模型&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专栏的文章图文并茂&#x…

MyBatis-plus(2)

实现逻辑查询: 1)and:其实如果只是想实现and查询&#xff0c;只是需要连续调用对应的方法或者是通过wrapper对象实现两次调用即可 2)and的嵌套:假设现在有这样一条语句 select * from user where username"张三" and (age>26 or userID <19)&#xff0c;这条SQ…

使用django的APP在前端上传excel通过post传给后端读取并打印

文章目录 前言前端后端 前言 备研了&#xff0c;博客许久未更了&#xff0c;但是学期末的大作业&#xff0c;遇到了问题并成功解决了&#xff0c;不得不记录一下。 前端 <form method"post" enctype"multipart/form-data" action"/insurance/up…