1.Spring用到的设计模式
- 代理模式:最常见的 AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理,
其中JDK代理实现代码如下所示:
public class ProxyHandler implements InvocationHandler {Object target;public ProxyHandler(Object target) {this.target=target;}public void before(String param) throws Throwable {if(!param.equals("magicalwolf"))throw new IllegalArgumentException();}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {before((String)args[0]);return method.invoke(target, args);}}public class Main {public static void main(String[] args) {Subject target=new RealSubject();Subject proxy=(Subject)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new ProxyHandler(target));proxy.request("magicalwolf");proxy.request("hello");}}
CGLIB代理实现如下:
public class RequestInterceptor implements MethodInterceptor {public void before(String param) throws Throwable {if(!param.equals("hello"))throw new IllegalArgumentException();}@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {before((String)args[0]);return proxy.invokeSuper(obj, args);//调用父类的方法}}public class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer(); //字节码增强器enhancer.setSuperclass(RealSubject.class); //代理类enhancer.setCallback(new RequestInterceptor());//回调方法Subject proxy = (Subject) enhancer.create();proxy.request("hello");}}
- 模版模式: 定义了一个在操作中的算法框架,而将一些具体步骤延迟到子类中,使子类看可以在不改变算法结构下即可重新定义该算法的某些特定步骤,主要是一些对数据库操作的类用到,比如 JdbcTemplate、JpaTemplate,因为查询数据库的建立连接、执行查询、关闭连接几个过程,非常适用于模板方法。 ```
//提交事务 protected abstract void doCommit(DefaultTransactionStatus status);
//回滚事务 protected abstract void doRollback(DefaultTransactionStatus status);
//开始事务 protected abstract void doBegin(Object transaction, TransactionDefinition definition)
//获取当前的事务对象 protected abstract Object doGetTransaction()
Spring框架启动也遵循如准备启动上下文,初始化BeanFactory、BeanFactory对象的前置处理与注册,消息发送器初始化,发送应用启动消息等等特定的特定启动流程,,将BeanFactory的初始化和刷新留在了具体的应用实现类去实现。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Overridepublic void refresh() throws BeansException, IllegalStateException {prepareRefresh();//子类实现初始化BeanFactory对象ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();prepareBeanFactory(beanFactory);postProcessBeanFactory(beanFactory);invokeBeanFactoryPostProcessors(beanFactory);registerBeanPostProcessors(beanFactory);initMessageSource();initApplicationEventMulticaster();onRefresh();registerListeners();finishBeanFactoryInitialization(beanFactory);finishRefresh();
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
// 两个抽象方法public abstract ConfigurableListableBeanFactory getBeanFactory()throws IllegalStateException;
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; }
- 工厂模式: 定义了用于创建对象的接口,让子类决定要创建哪个类的实例化,可以促进组件或类之间的松耦合,通过使用接口而不是将特定的类绑定到应用程序代码中,Spring框架使用工厂模式实现了 BeanFactory 和 ApplicationContext 接口,基于工厂模式为Spring应用程序创建Bean,并管理着每一个Bean的生命周期。如BeanFactory实例中的doGetBean方法可以根据使用者传入的名字,类型,参数等生成对象并返回。
public class StaticListableBeanFactory implements ListableBeanFactory {
private final Map<String, Object> beans;
protected
String beanName = transformedBeanName(name);Object beanInstance;Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);}
}
- 单例模式: 保证了一个类仅有的一个实例,并提供了一个访问它的全局访问点,提供控制器对关键类的访问,如DB的连接类或Hibernate中的SessionFactory类,节省了大量的内存,Spring框架中的Bean对象默认都是为单例,在Bean对象注册器实例上使用了Map来管理Bean对象,每次获取到的对象是从该单例容器中取出来的。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } } } return singletonObject; }
}
- 责任链模式: 可以避免发送者与请求者耦合在一起,让多个对象都有可能接收到请求,将这些对象连接成一条链,并且沿着这条链路传递请求,直到有对象处理为止;Spring中的Filter实现了责任链模式,管理者所有的Filter的顺序执行,可以对同一种对象资源实现不同业务场景的处理,达到业务解耦。[https://blog.csdn.net/lovejj1994/article/details/87457581](https://blog.csdn.net/lovejj1994/article/details/87457581)
public final class ApplicationFilterChain implements FilterChain {
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];private int pos = 0;private int n = 0;@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {internalDoFilter(request,response);}private void internalDoFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if (pos < n) {ApplicationFilterConfig filterConfig = filters[pos++];Filter filter = filterConfig.getFilter();filter.doFilter(request, response, this);}}
}
- 观察者模式: 定义了对象之间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都能得到通知并自动更新。在Spring框架中,观察者用于实现ApplicationContext的事件处理功能,为开发者提供了ApplicationEvent和ApplicationLIstneter接口来启用事件处理,任何Bean实现了SpringListner接口都会收到ApplicationEvent作为事件发布者推送的消息;[https://zhuanlan.zhihu.com/p/101141124](https://zhuanlan.zhihu.com/p/101141124)
@Service public class PublishService {
@Autowiredprivate ApplicationContext applicationContext;public void publishEvent() {applicationContext.publishEvent(new TestSuccessEvent(this));}
}
@Service public class ListenService {
@EventListener(TestSuccessEvent.class)public void test() {....}
}
@Configuration public class AsyncEventConfig {
@Bean(name = "applicationEventMulticaster")public ApplicationEventMulticaster simpleApplicationEventMulticaster() {SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());return eventMulticaster;}
}
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
.....@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}}
….. }
- 适配器模式: 将一个类的接口转换成希望的另外一个接口,Spring框架使用适配器模式实现了很多功能,常见的适配器模式的类有 配置适配器RequestMappinghandlerAdapter完成了从请求到方法的映射,返回值到对应的视图或页面的适配转换
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Beanpublic RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,@Qualifier("mvcConversionService") FormattingConversionService conversionService,@Qualifier("mvcValidator") Validator validator) {RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();.....return adapter;}
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
@Overrideprotected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ModelAndView mav;checkRequest(request);if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {mav = invokeHandlerMethod(request, response, handlerMethod);}}else {mav = invokeHandlerMethod(request, response, handlerMethod);}}else {mav = invokeHandlerMethod(request, response, handlerMethod);}if (!response.containsHeader(HEADER_CACHE_CONTROL)) {if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);}else {prepareResponse(response);}}return mav;}
}
- 建造者模式: 可以一步步构建一个复杂的对象,最终将返回完整的对象,对象创建的逻辑和过程是通用的,使用它来创建相同的类型的不同具体实现,隐藏了调用方调用代码时构建对象的细节。Spring框架中有一些功能实现了建造者模式如EmbeddedDatabaseBuilder、BeanDefinitionBuilder、MockMvcWebClientBuilder等
public class EmbeddedDatabaseBuilder {
......public EmbeddedDatabaseBuilder setName(String databaseName) {this.databaseFactory.setDatabaseName(databaseName);return this;}public EmbeddedDatabaseBuilder setType(EmbeddedDatabaseType databaseType) {this.databaseFactory.setDatabaseType(databaseType);return this;}public EmbeddedDatabaseBuilder setDataSourceFactory(DataSourceFactory dataSourceFactory) {Assert.notNull(dataSourceFactory, "DataSourceFactory is required");this.databaseFactory.setDataSourceFactory(dataSourceFactory);return this;}......
}
**2.IOC和AOP的理解**- IOC 叫做控制反转,指的是通过Spring来管理对象的创建、配置和生命周期,这样相当于把控制权交给了Spring,不需要人工来管理对象之间复杂的依赖关系,这样做的好处就是解耦。在Spring里面,主要提供了 BeanFactory 和 ApplicationContext 两种 IOC 容器。- AOP 叫做面向切面编程,是一个编程范式,目的就是提高代码的模块性。Spring AOP 基于动态代理的方式实现,如果是实现了接口的话就会使用 JDK 动态代理,反之则使用 CGLIB 代理,Spring中 AOP 的应用主要体现在 事务、日志、异常处理等方面,通过在代码的前后做一些增强处理,可以实现对业务逻辑的隔离,提高代码的模块化能力,同时也是解耦。Spring主要提供了 Aspect 切面、JoinPoint 连接点、PointCut 切入点、Advice 增强等实现方式。**3.几种代理方式的实现方式与区别**| 代理方式 | 实现 | 优点 | 缺点 | 特点 || --- | --- | --- | --- | --- || JDK静态代理 | 代理类与委托类实现同一接口,并且在代理类中需要硬编码接口 | 实现简单,容易理解 | 代理类需要硬编码接口,在实际应用中可能会导致重复编码,浪费存储空间并且效率很低 | 好像没啥特点 || JDK动态代理 | 代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理 | 不需要硬编码接口,代码复用率高 | 只能够代理实现了接口的委托类 | 底层使用反射机制进行方法的调用 || CGLIB动态代理 | 代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理 | 可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口 | 不能对final类以及final方法进行代理 | 底层将方法全部存入一个数组中,通过数组索引直接进行方法调用 |<br />**4. Spring AOP 和 AspectJ AOP 有什么区别?**Spring AOP 基于动态代理实现,属于运行时增强。<br />AspectJ 则属于编译时增强,主要有3种方式:- 编译时织入:指的是增强的代码和源代码我们都有,直接使用 AspectJ 编译器编译就行了,编译之后生成一个新的类,他也会作为一个正常的 Java 类装载到JVM;- 编译后织入:指的是代码已经被编译成 class 文件或者已经打成 jar 包,这时候要增强的话,就是编译后织入,比如你依赖了第三方的类库,又想对他增强的话,就可以通过这种方式;- 加载时织入:指的是在JVM加载类的时候进行织入.| **Spring AOP** | **AspectJ** || --- | --- || 在纯 Java 中实现 | 使用 Java 编程语言的扩展实现 || 不需要单独的编译过程 | 除非设置 LTW,否则需要 AspectJ 编译器 (ajc) || 只能使用运行时织入 | 运行时织入不可用。支持编译时、编译后和加载时织入 || 功能不强-仅支持方法级编织 | 更强大 - 可以编织字段、方法、构造函数、静态初始值设定项、最终类/方法等......。 || 只能在由 Spring 容器管理的 bean 上实现 | 可以在所有域对象上实现 || 仅支持方法执行切入点 | 支持所有切入点 || 代理是由目标对象创建的, 并且切面应用在这些代理上 | 在执行应用程序之前 (在运行时) 前, 各方面直接在代码中进行织入 || 比 AspectJ 慢多了 | 更好的性能 || 易于学习和应用 | 相对于 Spring AOP 来说更复杂 |**5.Spring框架的主要模块**<br /><br />[https://www.cnblogs.com/deng-cc/p/8846596.html](https://www.cnblogs.com/deng-cc/p/8846596.html)Spring的核心容器模块,其中包括:- Beans和Core模块,是框架的基础部分,提供IOC/DI的特性;- Context模块,构建于Core和Beans基础之上,进行了功能的扩展。ApplicationContext接口是该模块的关键;- Spring Expression Language模块,提供了一个强大的表达式语言,用于运行时查询和操纵对象Spring的AOP模块,其中包括:- AOP模块提供了一个符合AOP联盟标准的面向切面编程的实现;- Aspects模块提供了对AspectJ(一个AOP的开源框架)的集成支持;- Instrumentation模块提供了class instrumentation支持和classloader实现,可在特定应用服务器上使用Spring的数据库访问模块,其中包括:- JDBC模块,提供了一个JDBC抽象层,简化了访问数据库的方式;- ORM模块,为主流的“对象-关系映射型框架”(如Hibernate、MyBatis、JPA、JDO)提供了交互层;- OXM模块,提供了一个对Object/XML映射实现的抽象层;- JMS模块,即Java Messaging Service模块,主要包含了一些制造和消费消息的特性;- Transaction模块,支持编程和声明性的事务管理Spring的Web模块,其中包括:- Web模块提供了基础的面向web的集成特性,如多文件上传、使用Servlet Listeners初始化IOC容器以及一个面向web的应用上下文。它还包括Spring远程支持中web的相关部分;- Servlet模块,包括了Spring的Model-View-Controller(SpringMVC)的实现;- Portlet模块,提供了用于Portlet环境和Web-Servlet模块的实现Spring的测试模块,该模块支持使用JUnit和TestNG对Spring组件进行测试。**6.Bean的生命周期**<br />SpringBean 生命周期简单概括为4个阶段:1.实例化,创建Bean对象<br /> 加载所有的Bean定义,创建有序图,实例化运行BeanFactoryProcessor,这个阶段可自定义Bean;2.实例化每个Bean,并填充Bean对象属性;3.初始化- 如果实现了`xxxAware`接口,通过不同类型的Aware接口拿到Spring容器的资源,如果实现了BeanNameAware接口,就将Bean的ID传递给setBeanName(),如果实现了BeanFacotryAware接口,则将的Bean工厂引用传递到setBeanFactory(),如实现了的ApplicationContextAware接口,就将应用上下文本身引用传递到setApplicationContext();- 如果实现了BeanPostProcessor接口,则会回调该接口的`postProcessBeforeInitialzation`和`postProcessAfterInitialization`方法;- 如果实现了InitializingBean接口,Spring会调用afterPropertiesSet()方法来初始化或加载申请的应用资源;- 如果配置了`init-method`方法,则会执行`init-method`配置的方法4.销毁- 容器关闭后,如果Bean实现了`DisposableBean`接口,则会回调该接口的`destroy`方法- 如果配置了`destroy-method`方法,则会执行`destroy-method`配置的方法**7.什么是循环依赖?怎样解决?**首先,Spring 解决循环依赖有两个前提条件:1. 不全是构造器方式的循环依赖1. 必须是单例Bean的生命周期本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化完全的对象。<br />一级缓存:用来保存实例化、初始化都完成的对象<br />二级缓存:用来保存实例化完成,但是未初始化完成的对象<br />三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象假设一个简单的循环依赖场景,A、B互相依赖。<br /><br />A对象的创建过程:1. 创建对象A,实例化的时候把A对象工厂放入三级缓存1. A注入属性时,发现依赖B,转而去实例化B1. 同样创建对象B,注入属性时发现依赖A,一次从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入一级缓存。1. 接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存1. 最后,一级缓存中保存着实例化、初始化都完成的A、B对象<br />因此,由于把实例化和初始化的流程分开了,所以如果都是用构造器的话,就没法分离这个操作,所以都是构造器的话就无法解决循环依赖的问题了。
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//…
try {
singletonObject = singletonFactory.getObject();
}
//…
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
//将对象添加到单例注册表
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
}
}
}
**8.Spring启动流程**<br />这个流程,网上一搜基本都是这张图了,那其实主要的流程就几个步骤:1. 准备环境,根据不同的环境创建不同的Environment1. 准备、加载上下文,为不同的环境选择不同的Spring Context,然后加载资源,配置Bean1. 初始化,这个阶段刷新Spring Context,启动应用1. 最后结束流程[](https://www.cnblogs.com/sword-successful/p/11383723.html)**8.Spring事务实现与传播机制**- **PROPAGATION_REQUIRED**:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这也是通常我们的默认选择。- **PROPAGATION_REQUIRES_NEW**:创建新事务,无论当前存不存在事务,都创建新事务。- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。- PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。- PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘**9.依赖注入模式有哪些?****依赖注入是一种解决类之间依赖关系的设计模式,而其依赖关系只是对象属性。必需使用构造方法注入或setter注入为依赖对象构造注入器,构造方法注入是在创建赋值这些对象属性以实例化对象的方法之一。**| 构造方法注入 | setter注入 || --- | --- || 拥有构造方法的类接受参数,有时非常紧凑,并且很清楚创建了什么 | 对象是构造的,但不清楚其属性是否已经初始化 || 当依赖项是必需的时候,这是一个非常好的选择 | 当依赖项不是必需的时候,是个合适的选择 || 允许隐藏不可变的对象属性,因为它没有这些对象的set方法,要确保对象的不可变性,请使用构造方法注入模式 | 不能保证对象的不可变性 || 可能在应用程序中创建循环依赖项 | 可以解决应用程序中的循环依赖问题 |**10.理解Bean作用域**<br />在Spring中,每个Bean在容器中都有一个作用域。 这不仅可控制Bean的元数据和生命周期,还可以控制这个Bean的作用域,我们可以创建自定义的作用域,然后将其注册到容器中。- 单例作用域:Spring应用上下文通过单例作用域来创建Bean,可以有效降低实例化的成本,非常适用于应用中的无状态对象;- 原型作用域:Spring应用上下文提供了原型作用域来保存某些线程不安全的对象状态,以便后面重用.- 会话作用域: 仅为Web环境的每个用户session创建一个新的实例- 请求作用域: 仅为Web环境的每个请求创建一个的新的实例- WebSocket作用域/Refresh作用域/线程作用域也可自定义作用域类,只要实现了org.springframework.Beans.factory.config.scope接口,就可以作为Spring Ioc容器的自定义作用域。如下所示就是自定义的作用域。
public class MyScope implements Scope {
private final ThreadLocal<Object> myThreadScope = new ThreadLocal<Object>() {protected Map<String, Object> initialValue() {return new HashMap<String, Object>();}}
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map
@Override
public Object remove(String name) {
return ((Map
}
Scope threadScope = new MyScope(); beanFactory.registerScope(“thread”, threadScope); ```
