面试实战 问题三十五 Spring bean 的自动装配 介绍一下熟悉的几种设计模式 Java 四种线程池是哪些

面试实战 问题三十五 Spring bean 的自动装配 介绍一下熟悉的几种设计模式 Java 四种线程池是哪些

Spring bean 的自动装配

Spring Bean 自动装配详解

一、自动装配概念

自动装配是 Spring 容器自动建立 Bean 之间依赖关系的机制。它通过扫描上下文,自动将符合条件 的 Bean 注入到目标属性中,无需手动配置 <property><constructor-arg> 元素。核心优势在于简化配置降低耦合度

二、装配方式及使用方法
1. XML 配置方式

<bean> 标签中设置 autowire 属性:

xml 复制代码
<bean id="people" class="com.example.People" autowire="byType">
    <property name="name" value="张三"/>
</bean>
  • byName

    按属性名匹配:容器查找与属性名称相同 的 Bean ID 进行注入
    示例people 类有 dog 属性 → 注入 ID 为 dog 的 Bean

  • byType

    按类型匹配:容器查找同类型 的 Bean(需确保同类 Bean 唯一)
    示例people 类有 Animal 类型属性 → 注入 Animal 实现类的 Bean

  • constructor

    按构造函数参数类型自动装配(类似 byType)

2. 注解方式(推荐)

步骤 1:启用注解扫描

xml 复制代码
<context:component-scan base-package="com.example"/>

或使用 Java 配置:

java 复制代码
@Configuration
@ComponentScan("com.example")
public class AppConfig {}

步骤 2:常用注解

  • @Autowired

    按类型自动注入(可标记在字段/构造器/方法上)

    java 复制代码
    @Service
    public class UserService {
        @Autowired
        private UserDao userDao; // 自动注入UserDao实现类
    }
  • @Qualifier

    解决同类型多个 Bean 的歧义,指定 Bean 名称

    java 复制代码
    @Autowired
    @Qualifier("mysqlDao")
    private DatabaseDao databaseDao;
  • @Resource

    JSR-250 标准注解,默认按名称匹配(name 属性)

    java 复制代码
    @Resource(name = "reportService")
    private ReportService service;
3. 测试示例

引用中的单元测试代码:

java 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class TestService {
    @Autowired
    private UserService userService; // 自动装配

    @Test
    public void testInjection() {
        assertNotNull(userService); // 验证注入成功
    }
}
三、装配规则与注意事项
  1. 优先级:注解装配 > XML 显式配置 > 自动装配
  2. 冲突解决
    • 同类型多个 Bean 时:@Qualifier 指定名称或使用 @Primary 标记首选 Bean
    • XML 中可设置 autowire-candidate="false" 排除候选
  3. 限制
    • 基本数据类型(如 int)无法自动装配
    • 容器中必须存在唯一匹配的 Bean(byType 要求)

最佳实践 :推荐使用 注解驱动 方式,结合 @ComponentScan@Autowired,保持代码简洁性和可维护性。


介绍一下熟悉的几种设计模式

单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点。在 Java 中,常见的实现方式有饿汉式和懒汉式。

饿汉式
java 复制代码
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

饿汉式在类加载时就创建了实例,因此是线程安全的。

懒汉式(线程安全)
java 复制代码
public class Singleton {
    private static volatile Singleton INSTANCE;

    private Singleton() {}

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

懒汉式在第一次调用 getInstance() 方法时才创建实例,使用双重检查锁定确保线程安全。

工厂模式

工厂模式定义一个创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。

java 复制代码
// 产品接口
interface Product {
    void operation();
}

// 具体产品
class ConcreteProduct implements Product {
    @Override
    public void operation() {
        System.out.println("ConcreteProduct operation");
    }
}

// 工厂接口
interface Factory {
    Product createProduct();
}

// 具体工厂
class ConcreteFactory implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProduct();
    }
}

工厂模式将对象的创建和使用分离,提高了代码的可维护性和可扩展性。

代理模式

代理模式主要使用了 Java 的多态,代理类负责接收请求,然后将请求委托给被代理类处理。代理类和被代理类实现同一个接口,以确保它们具有相同的行为。

java 复制代码
// 主题接口
interface Subject {
    void visit();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void visit() {
        System.out.println("RealSubject visit");
    }
}

// 代理主题
class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void visit() {
        // 可以在调用真实主题方法前后添加额外的逻辑
        System.out.println("Before RealSubject visit");
        realSubject.visit();
        System.out.println("After RealSubject visit");
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
    }
}

代理模式可以在不修改被代理类的情况下,对其功能进行增强。

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的状态。

java 复制代码
import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }
}

// 观察者接口
interface Observer {
    void update(int state);
}

// 具体观察者
class ConcreteObserver implements Observer {
    @Override
    public void update(int state) {
        System.out.println("Received state update: " + state);
    }
}

观察者模式实现了对象之间的松散耦合,当一个对象的状态发生变化时,其他依赖它的对象能够自动得到通知并更新。

Java 四种线程池是哪些

Java 通过 Executors 提供四种线程池,分别为 CachedThreadPoolFixedThreadPoolSingleThreadExecutorScheduledThreadPool,以下是具体介绍:

CachedThreadPool(可缓存线程池)

可缓存线程池会根据需要创建新线程,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。该线程池只有非核心线程,线程数量完全弹性。示例代码如下:

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
            });
        }
        executor.shutdown();
    }
}

FixedThreadPool(定长线程池)

定长线程池可控制线程最大并发数,超出的线程会在队列中等待。该线程池只有核心线程,线程数量完全固定。示例代码如下:

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
            });
        }
        executor.shutdown();
    }
}

SingleThreadExecutor(单线程池)

单线程化的线程池只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO、LIFO、优先级)执行。该线程池只能实现排队等待,完全没有并发。示例代码如下:

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
            });
        }
        executor.shutdown();
    }
}

ScheduledThreadPool(调度线程池)

调度线程池支持定时及周期性任务执行,非核心线程数没有上限。该线程池可实现延时任务和周期任务。示例代码如下:

java 复制代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
        executor.schedule(() -> {
            System.out.println("Delayed task is running on thread " + Thread.currentThread().getName());
        }, 2, TimeUnit.SECONDS);

        executor.scheduleAtFixedRate(() -> {
            System.out.println("Periodic task is running on thread " + Thread.currentThread().getName());
        }, 1, 1, TimeUnit.SECONDS);
    }
}
相关推荐
2301_805962935 小时前
嘉立创EDA添加自己的元件和封装
java·开发语言
TimberWill5 小时前
MinIO整合SpringBoot实现获取文件夹目录结构及文件内容
java·linux·springboot
崎岖Qiu5 小时前
【设计模式笔记18】:并发安全与双重检查锁定的单例模式
java·笔记·单例模式·设计模式
曲莫终5 小时前
spring.main.lazy-initialization配置的实现机制
java·后端·spring
CodersCoder5 小时前
SpringAI-Tool简单实践
spring·spring-ai
❀͜͡傀儡师5 小时前
docker部署Docker Compose文件Web管理工具Dockman
java·前端·docker·dockman
沐雪架构师5 小时前
大模型Agent面试精选题(第五辑)-Agent提示词工程
java·面试·职场和发展
云飞云共享云桌面5 小时前
SolidWorks服务器怎么实现研发软件多人共享、数据安全管理
java·linux·运维·服务器·数据库·自动化
是喵斯特ya5 小时前
JNDI注入漏洞分析
java·安全