面试时如何展示Spring设计模式:你知道Spring如何实现这些“幕后黑手”吗?

0 阅读5分钟

在面试时,设计模式总是一个经典的问题。面试官希望你不仅能够背出模式的名字,还能结合实际代码进行深入分析,尤其是在Spring框架中的实现。Spring框架背后巧妙地使用了许多经典的设计模式,让我们来看看这些模式如何在Spring中发挥作用,并且教你如何通过实际代码展示这些设计模式在面试中的应用。

1. 单例模式:Spring容器中的VIP客户

单例模式确保一个类只有一个实例,并且该实例在整个应用中是共享的。Spring中,所有默认的Bean都是单例的。容器初始化时会创建一个实例,之后再也不会创建新的对象。

代码示例:

@Configuration
public class AppConfig {

    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
}

分析:

  • @Bean 注解的userService()方法返回一个UserServiceImpl实例。
  • 因为Spring默认使用单例模式,所以UserService的实例会在容器启动时创建一次,之后每次请求都会返回同一个实例。
  • 这样可以避免频繁创建对象,节省内存,提高性能。

2. 工厂模式:Spring的“定制工厂”

工厂模式通过工厂类来创建对象。在Spring中,BeanFactoryApplicationContext就充当了“工厂”的角色,它们负责管理Bean的创建和生命周期。

代码示例:

public interface BeanFactory {
    Object getBean(String beanName) throws BeansException;
    boolean containsBean(String name);
    boolean isSingleton(String name);
    boolean isPrototype(String name);
    Class<?> getType(String name);
}

分析:

  • BeanFactory 是一个接口,定义了Spring容器如何获取和管理Bean的基本操作。
  • getBean() 方法用于返回指定名称的Bean实例,isSingleton() 判断该Bean是否为单例。
  • 这种设计将Bean的创建和管理解耦,你不需要关心对象的创建过程,Spring容器会根据配置动态创建和管理这些对象。

实现示例:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory {
    protected Map<String, BeanDefinition> beanDefinitionMap = 
        new ConcurrentHashMap<>(256);

    @Override
    public Object getBean(String beanName) throws BeansException {
        Object singleton = getSingleton(beanName);
        if (singleton == null) {
            singleton = createBean(beanName);
        }
        return singleton;
    }
}

分析:

  • DefaultListableBeanFactoryBeanFactory 接口的一个实现。
  • 通过 getBean() 方法,它首先会尝试从缓存中获取已经存在的单例Bean(通过getSingleton())。如果找不到,它会创建一个新的Bean(通过createBean())。
  • DefaultListableBeanFactory 会通过管理一个beanDefinitionMap来存储所有的Bean定义,这个Map包含了所有Bean的配置信息。

3. 代理模式:AOP中的“幕后英雄”

Spring的AOP(面向切面编程)是通过代理模式来增强目标对象的功能,比如事务管理、日志记录等。Spring可以通过JdkDynamicAopProxyCglib动态代理来创建代理对象。

代码示例:

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Method " + joinPoint.getSignature().getName() + " is about to be called");
    }
}

分析:

  • @Aspect 注解标记了这个类为一个切面,它会对com.example.service包下的所有方法进行增强。
  • @Before 注解表示方法会在目标方法执行前执行。这里是日志记录增强,可以在方法执行前输出方法名称。
  • Spring通过代理模式,在目标方法执行前后插入增强逻辑(如日志记录、事务处理等),从而不改变原有的业务逻辑代码。

4. JdkDynamicAopProxy:Spring的代理超级英雄

Spring使用动态代理(基于JdkDynamicAopProxy)来在运行时生成代理类,这样我们就不需要手动为每个目标类创建代理对象了。代理对象负责调用目标方法,并且可以在调用时增加其他逻辑。

代码示例:

public class JdkDynamicAopProxy implements AopProxy {

    private final AdvisedSupport advised;

    public JdkDynamicAopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader, advised.getTargetClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, advised.getTarget(), method, args);
                    return advised.getMethodInterceptor().invoke(invocation);
                }
            });
    }
}

分析:

  • JdkDynamicAopProxy 利用Java的反射机制,创建了一个代理对象。这个对象实现了目标对象的接口,并通过 InvocationHandler 来处理方法调用。
  • Proxy.newProxyInstance() 方法动态生成代理类,代理对象会将方法调用转发给目标对象,同时可以通过 MethodInterceptor 增强目标方法的行为(如事务、日志等)。

5. ApplicationListener:Spring的“耳朵”

ApplicationListener 是Spring事件机制中的一部分,类似于观察者模式。通过它,我们可以监听Spring容器中的各种事件,做出相应的处理。

代码示例:

@Component
public class EventListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("ApplicationContext is refreshed!");
    }
}

分析:

  • ApplicationListener 接口允许我们定义事件处理逻辑,在事件发生时执行特定的操作。
  • 这个例子中,EventListener 监听了 ContextRefreshedEvent 事件,每次 Spring 容器刷新时,onApplicationEvent() 方法就会被调用。你可以在这个方法里编写自定义的处理逻辑。

面试官会怎么反应?

如果你能在面试中通过实际的代码示例来展示Spring如何实现设计模式,面试官肯定会对你产生浓厚的兴趣。你不仅能背出设计模式的定义,还能结合实际项目中Spring的实现,展示你对技术的深刻理解。

小结:设计模式,不仅要记住,还要灵活运用

通过这篇文章,我们展示了Spring框架如何使用设计模式来提高开发效率。Spring不仅仅是用这些模式来“装饰”代码,更通过它们让开发过程更加灵活和高效。

下次面试时,准备好这些设计模式的实际应用代码,让面试官看到你不仅掌握了理论,更能把它们灵活地运用到实际开发中!