面试实战 问题三十五 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; -
@ResourceJSR-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); // 验证注入成功
}
}
三、装配规则与注意事项
- 优先级:注解装配 > XML 显式配置 > 自动装配
- 冲突解决 :
- 同类型多个 Bean 时:
@Qualifier指定名称或使用@Primary标记首选 Bean - XML 中可设置
autowire-candidate="false"排除候选
- 同类型多个 Bean 时:
- 限制 :
- 基本数据类型(如 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 提供四种线程池,分别为 CachedThreadPool、FixedThreadPool、SingleThreadExecutor 和 ScheduledThreadPool,以下是具体介绍:
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);
}
}