Skip to content

Spring核心面试题

1. Spring框架的基本概念

问题:什么是Spring框架?

答案: Spring框架是一个轻量级的Java企业级应用开发框架,它提供了依赖注入、AOP、事务管理等核心功能,简化了企业级应用的开发。

2. Spring框架的核心模块

问题:Spring框架的核心模块有哪些?

答案

  • Spring Core:提供IoC容器和依赖注入功能。
  • Spring AOP:提供面向切面编程功能。
  • Spring JDBC:提供JDBC抽象层,简化数据库操作。
  • Spring ORM:提供对象关系映射功能,支持Hibernate、JPA等。
  • Spring MVC:提供Web MVC框架。
  • Spring Security:提供安全认证和授权功能。
  • Spring Test:提供测试支持。

3. IoC容器

问题:什么是IoC容器?Spring中的IoC容器有哪些?

答案

  • IoC(Inversion of Control):控制反转,将对象的创建和依赖关系的管理交给容器,而不是由对象自己管理。
  • Spring中的IoC容器
    • BeanFactory:基础的IoC容器,提供基本的依赖注入功能。
    • ApplicationContext:高级的IoC容器,继承自BeanFactory,提供更多功能,如国际化、事件发布等。

4. 依赖注入

问题:什么是依赖注入?Spring中依赖注入的方式有哪些?

答案

  • 依赖注入(Dependency Injection):将对象的依赖关系由容器注入,而不是由对象自己创建或查找。
  • 依赖注入的方式
    • 构造器注入:通过构造方法注入依赖。
    • Setter注入:通过setter方法注入依赖。
    • 字段注入:通过@Autowired注解注入依赖。

示例

java
// 构造器注入
public class UserService {
    private UserDao userDao;
    
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

// Setter注入
public class UserService {
    private UserDao userDao;
    
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

// 字段注入
public class UserService {
    @Autowired
    private UserDao userDao;
}

5. Bean的作用域

问题:Spring中Bean的作用域有哪些?

答案

  • singleton:单例,默认作用域,整个应用中只有一个Bean实例。
  • prototype:原型,每次获取Bean时都创建一个新的实例。
  • request:请求,每个HTTP请求创建一个新的实例。
  • session:会话,每个HTTP会话创建一个新的实例。
  • application:应用,每个ServletContext创建一个新的实例。
  • websocket:WebSocket,每个WebSocket会话创建一个新的实例。

6. Bean的生命周期

问题:Spring中Bean的生命周期是什么?

答案

  1. 实例化:创建Bean实例。
  2. 属性赋值:设置Bean的属性。
  3. 初始化前:调用BeanPostProcessor的postProcessBeforeInitialization方法。
  4. 初始化:调用Bean的初始化方法(如@PostConstruct注解的方法、实现InitializingBean接口的afterPropertiesSet方法)。
  5. 初始化后:调用BeanPostProcessor的postProcessAfterInitialization方法。
  6. 使用:Bean可以被使用。
  7. 销毁:调用Bean的销毁方法(如@PreDestroy注解的方法、实现DisposableBean接口的destroy方法)。

7. AOP

问题:什么是AOP?Spring中的AOP实现方式有哪些?

答案

  • AOP(Aspect-Oriented Programming):面向切面编程,通过横切关注点的方式,将与业务逻辑无关的代码(如日志、事务)分离出来。
  • Spring中的AOP实现方式
    • 基于代理的AOP:使用JDK动态代理或CGLIB代理。
    • 基于AspectJ的AOP:使用AspectJ实现更复杂的AOP功能。

8. AOP的核心概念

问题:AOP的核心概念有哪些?

答案

  • 切面(Aspect):横切关注点的模块化。
  • 连接点(Join Point):程序执行过程中的点,如方法调用、异常抛出等。
  • 通知(Advice):在连接点执行的代码,包括前置通知、后置通知、环绕通知、异常通知、最终通知。
  • 切点(Pointcut):定义哪些连接点会被通知。
  • 引入(Introduction):向现有类添加新的方法或属性。
  • 目标对象(Target Object):被AOP代理的对象。
  • 代理(Proxy):AOP创建的对象,包含目标对象和通知。

9. Spring中的事务管理

问题:Spring中的事务管理方式有哪些?

答案

  • 编程式事务:通过代码手动管理事务。
  • 声明式事务:通过注解或XML配置管理事务。

示例

java
// 编程式事务
@Autowired
private PlatformTransactionManager transactionManager;

public void transfer(int fromId, int toId, double amount) {
    TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    try {
        // 业务逻辑
        accountDao.decrease(fromId, amount);
        accountDao.increase(toId, amount);
        transactionManager.commit(status);
    } catch (Exception e) {
        transactionManager.rollback(status);
        throw e;
    }
}

// 声明式事务
@Transactional
public void transfer(int fromId, int toId, double amount) {
    accountDao.decrease(fromId, amount);
    accountDao.increase(toId, amount);
}

10. 事务的隔离级别

问题:Spring中事务的隔离级别有哪些?

答案

  • DEFAULT:使用数据库默认的隔离级别。
  • READ_UNCOMMITTED:读取未提交的数据,可能导致脏读、不可重复读、幻读。
  • READ_COMMITTED:读取已提交的数据,可能导致不可重复读、幻读。
  • REPEATABLE_READ:可重复读,可能导致幻读。
  • SERIALIZABLE:串行化,最严格的隔离级别,避免所有并发问题。

11. 事务的传播行为

问题:Spring中事务的传播行为有哪些?

答案

  • REQUIRED:如果当前存在事务,则加入事务;否则创建新事务。
  • SUPPORTS:如果当前存在事务,则加入事务;否则以非事务方式执行。
  • MANDATORY:如果当前存在事务,则加入事务;否则抛出异常。
  • REQUIRES_NEW:创建新事务,暂停当前事务。
  • NOT_SUPPORTED:以非事务方式执行,暂停当前事务。
  • NEVER:以非事务方式执行,如果当前存在事务则抛出异常。
  • NESTED:如果当前存在事务,则创建嵌套事务;否则创建新事务。

12. Spring中的注解

问题:Spring中常用的注解有哪些?

答案

  • @Component:标记一个类为Spring组件。
  • @Controller:标记一个类为控制器。
  • @Service:标记一个类为服务。
  • @Repository:标记一个类为数据访问层。
  • @Autowired:自动注入依赖。
  • @Qualifier:指定注入的Bean名称。
  • @Value:注入属性值。
  • @Configuration:标记一个类为配置类。
  • @Bean:标记一个方法返回的对象为Spring Bean。
  • @Transactional:标记一个方法需要事务支持。
  • @Aspect:标记一个类为切面。

13. Spring中的配置方式

问题:Spring中的配置方式有哪些?

答案

  • XML配置:使用XML文件配置Bean。
  • 注解配置:使用注解配置Bean。
  • Java配置:使用Java类配置Bean。

示例

xml
<!-- XML配置 -->
<bean id="userService" class="com.example.UserService">
    <property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.example.UserDao"/>

<!-- 注解配置 -->
@Component
public class UserService {
    @Autowired
    private UserDao userDao;
}

@Component
public class UserDao {
}

<!-- Java配置 -->
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        UserService userService = new UserService();
        userService.setUserDao(userDao());
        return userService;
    }
    
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}

14. Spring中的事件机制

问题:Spring中的事件机制是什么?

答案: Spring中的事件机制基于观察者模式,通过ApplicationEvent和ApplicationListener实现。

示例

java
// 自定义事件
public class CustomEvent extends ApplicationEvent {
    public CustomEvent(Object source) {
        super(source);
    }
}

// 事件发布者
@Service
public class EventPublisher {
    @Autowired
    private ApplicationEventPublisher publisher;
    
    public void publishEvent() {
        publisher.publishEvent(new CustomEvent(this));
    }
}

// 事件监听器
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("Received custom event: " + event);
    }
}

15. Spring中的资源管理

问题:Spring中的资源管理是什么?

答案: Spring中的资源管理通过Resource接口和ResourceLoader实现,用于加载各种资源,如文件、URL等。

示例

java
@Autowired
private ResourceLoader resourceLoader;

public void loadResource() {
    Resource resource = resourceLoader.getResource("classpath:config.properties");
    try (InputStream inputStream = resource.getInputStream()) {
        // 读取资源
    } catch (IOException e) {
        e.printStackTrace();
    }
}

16. Spring中的国际化

问题:Spring中的国际化如何实现?

答案: Spring中的国际化通过MessageSource接口实现,支持多语言消息。

示例

java
@Autowired
private MessageSource messageSource;

public void getMessage() {
    String message = messageSource.getMessage("greeting", new Object[] {"John"}, Locale.ENGLISH);
    System.out.println(message);
}

17. Spring中的类型转换

问题:Spring中的类型转换如何实现?

答案: Spring中的类型转换通过ConversionService和Converter接口实现,用于在不同类型之间进行转换。

示例

java
// 自定义转换器
public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        try {
            return new SimpleDateFormat("yyyy-MM-dd").parse(source);
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

// 配置转换器
@Configuration
public class AppConfig {
    @Bean
    public ConversionService conversionService() {
        DefaultConversionService conversionService = new DefaultConversionService();
        conversionService.addConverter(new StringToDateConverter());
        return conversionService;
    }
}

18. Spring中的数据绑定

问题:Spring中的数据绑定如何实现?

答案: Spring中的数据绑定通过DataBinder实现,用于将请求参数绑定到对象。

示例

java
public void bindData() {
    User user = new User();
    DataBinder binder = new DataBinder(user);
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("name", "John");
    parameters.put("age", "30");
    binder.bind(new MutablePropertyValues(parameters));
    System.out.println(user.getName()); // John
    System.out.println(user.getAge()); // 30
}

19. Spring中的校验

问题:Spring中的校验如何实现?

答案: Spring中的校验通过Validator接口和JSR-303/JSR-349实现,用于验证对象的属性。

示例

java
// 实体类
public class User {
    @NotNull
    @Size(min = 2, max = 30)
    private String name;
    
    @Min(18)
    private int age;
    
    // getters and setters
}

// 校验
@Autowired
private Validator validator;

public void validateUser() {
    User user = new User();
    user.setName("J"); // 长度不足
    user.setAge(15); // 年龄不足
    
    Set<ConstraintViolation<User>> violations = validator.validate(user);
    for (ConstraintViolation<User> violation : violations) {
        System.out.println(violation.getMessage());
    }
}

20. Spring中的异步处理

问题:Spring中的异步处理如何实现?

答案: Spring中的异步处理通过@Async注解和TaskExecutor实现,用于执行异步任务。

示例

java
// 配置异步执行器
@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        return executor;
    }
}

// 异步方法
@Service
public class AsyncService {
    @Async
    public void asyncMethod() {
        // 异步执行的代码
    }
}

21. Spring中的缓存

问题:Spring中的缓存如何实现?

答案: Spring中的缓存通过@Cacheable、@CachePut、@CacheEvict等注解实现,支持多种缓存实现。

示例

java
// 配置缓存
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("users")));
        return cacheManager;
    }
}

// 缓存方法
@Service
public class UserService {
    @Cacheable("users")
    public User getUserById(int id) {
        // 从数据库获取用户
        return userDao.findById(id);
    }
    
    @CachePut("users")
    public User updateUser(User user) {
        // 更新用户
        return userDao.update(user);
    }
    
    @CacheEvict("users")
    public void deleteUser(int id) {
        // 删除用户
        userDao.delete(id);
    }
}

22. Spring中的测试

问题:Spring中的测试如何实现?

答案: Spring中的测试通过Spring Test框架实现,支持单元测试和集成测试。

示例

java
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService userService;
    
    @Test
    public void testGetUserById() {
        User user = userService.getUserById(1);
        assertNotNull(user);
        assertEquals("John", user.getName());
    }
}

23. Spring中的安全

问题:Spring中的安全如何实现?

答案: Spring中的安全通过Spring Security实现,提供认证和授权功能。

示例

java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER")
                .and()
                .withUser("admin").password("password").roles("ADMIN");
    }
}

24. Spring中的远程调用

问题:Spring中的远程调用如何实现?

答案: Spring中的远程调用通过RMI、Hessian、Burlap、HTTP Invoker等实现。

示例

java
// 暴露RMI服务
@Configuration
public class RmiConfig {
    @Bean
    public RmiServiceExporter rmiServiceExporter(UserService userService) {
        RmiServiceExporter exporter = new RmiServiceExporter();
        exporter.setService(userService);
        exporter.setServiceName("UserService");
        exporter.setServiceInterface(UserService.class);
        return exporter;
    }
}

// 调用RMI服务
@Configuration
public class RmiClientConfig {
    @Bean
    public UserService userService() {
        RmiProxyFactoryBean factoryBean = new RmiProxyFactoryBean();
        factoryBean.setServiceUrl("rmi://localhost:1099/UserService");
        factoryBean.setServiceInterface(UserService.class);
        factoryBean.afterPropertiesSet();
        return (UserService) factoryBean.getObject();
    }
}

25. Spring中的批处理

问题:Spring中的批处理如何实现?

答案: Spring中的批处理通过Spring Batch实现,用于处理大量数据。

示例

java
@Configuration
@EnableBatchProcessing
public class BatchConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    
    @Bean
    public Job importUserJob() {
        return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .flow(step1())
            .end()
            .build();
    }
    
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
            .<User, User>chunk(10)
            .reader(reader())
            .processor(processor())
            .writer(writer())
            .build();
    }
    
    @Bean
    public ItemReader<User> reader() {
        // 实现ItemReader
    }
    
    @Bean
    public ItemProcessor<User, User> processor() {
        // 实现ItemProcessor
    }
    
    @Bean
    public ItemWriter<User> writer() {
        // 实现ItemWriter
    }
}