Spring框架中都用到了哪些设计模式?
代理模式—在AOP和remoting中被用的比较多。
单例模式—在spring配置文件中定义的bean默认为单例模式。
模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate
, JpaTemplate。
工厂模式—BeanFactory用来创建对象的实例。
适配器–spring aop
装饰器–spring data hashmapper
观察者– spring 时间驱动模型
回调–Spring ResourceLoaderAware回调接口
前端控制器–spring用前端控制器DispatcherServlet对请求进行分发
Spring中Bean的生命周期和作用域各是怎样的?
1.首先容器启动后找到Bean定义信息调用构造方法并将其初始化;
2.按照Bean定义配置信息,注入所有的属性;
3.如果Bean实现了各种XXXAware接口,会回调该接口的setXXX()方法;
4.如果Bean含有@PostConstruct注解,则会调用该方法;若bean实现了BeanPostProcessor接口,将调用它的postProcessBeforeInitialization接口方法;
5.如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法;
6.如果Bean配置了init-method方法,则会执行init-method配置的方法;若bean实现了BeanPostProcessor接口,将调用它的postProcessBeforeInitialization接口方法;
7.经过流程6之后,就可以正式使用该Bean了;容器关闭后,@PreDestroy调用该方法;
8.如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法;
9.如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法。
Spring对象初始化bean时机
在默认情况下,只要在Spring容器中配置了一个bean,容器在启动时就会实例化该bean,单例模式。如果在Spring配制文件时设置懒加载模式(lazy-init=”true”),在getBean时才会实例化对象。如果scope=”prototype”时,无论lazy-init的值是什么都只会在使用时才会创建,当struts2的action和spring容器整合的时候,action的scope设置成prototype。
Spring当中bean的作用域
singleton:单例模式,Spring IoC容器中只会存在一个共享的Bean实例;
prototype:原型模式,每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态;
request:在一次Http请求中,容器会返回该Bean的同一实例。而对不同的Http请求则会产生新的Bean,而且该bean仅在当前Http Request内有效;
session:在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效;
global Session:在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。
Spring AOP无法代理方法内部调用的原因?
在使用Spring AOP的时候,我们从IOC容器中获取的Bean对象其实都是代理对象,而不是那些Bean对象本身,由于this关键字引用的并不是该Bean对象的代理对象,而是其本身,因此Spring AOP是不能拦截到这些被嵌套调用的方法的。
Spring Bean的加载过程是怎样的?
1、ResourceLoader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件的资源;
2、BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
3、容器扫描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射机制自动识别出Bean工厂后处理后器(实现BeanFactoryPostProcessor接口)的Bean,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理。主要完成以下两项工作:
1)对使用到占位符的<bean>元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BeanDefinition对象进行加工处理并得到成品的BeanDefinition对象;
2)对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor接口的Bean),并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry);
4.Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStrategy着手进行Bean实例化的工作;
5.在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作;
6.利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。
SpringMVC执行流程和工作原理
1、用户发送请求至前端控制器DispatcherServlet。
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器(根据请求的url查找Handler)。
3、HandlerMapping找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器生成HandlerExecutionChain一并返回给DispatcherServlet。
4、DispatcherServlet调用HandlerAdapter处理器适配器。
5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
HandlerMapping和HandlerAdapter区别:前者是用来找到url对应的处理handler对象,而不是找到url对应的处理函数。后者则是用来匹配到handler的某个具体的处理函数上,准备参数并调度执行这个函数。
6、Controller执行完成返回ModelAndView。HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
7、DispatcherServlet将ModelAndView传给ViewReslover视图解析器,ViewReslover解析后返回具体View。
8、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)并响应给用户。
BeanFactory 和 ApplicationContext 有什么区别
beanfactory顾名思义,它的核心概念就是bean工厂,用作于bean生命周期的管理,而applicationcontext这个概念就比较丰富了,单看名字(应用上下文)就能看出它包含的范围更广,它继承自bean factory但不仅仅是继承自这一个接口,还有继承了其他的接口,所以它不仅仅有bean factory相关概念,更是一个应用系统的上下文,其设计初衷应该是一个包罗万象的对外暴露的一个综合的API。
如何自定义注解实现功能
大致流程为:
1. 新建一个注解@MyLog,加在需要注解申明的方法上面
2. 新建一个类MyLogAspect,通过@Aspect注解使该类成为切面类。
3. 通过@Pointcut 指定切入点 ,这里指定的切入点为MyLog注解类型,也就是被@MyLog注解修饰的方法,进入该切入点。
4. MyLogAspect中的方法通过加通知注解(@Before、@Around、@AfterReturning、@AfterThrowing、@After等各种通知)指定要做的业务操作。
BeanFactory和FactoryBean的区别
BeanFactory是IOC最基本的容器,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。
FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。
BeanFactory和FactoryBean其实没有什么比较性的,只是两者的名称特别接近,所以有时候会拿出来比较一番,BeanFactory是提供了OC容器最基本的形式,给具体的IOC容器的实现提供了规范,FactoryBean可以说为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类,要想深入准确的理解FactoryBean,只有去读读Spring源码了。
Spring是如何管理事务的
spring的事务包括编程式事务和声明式事务。
编程式事务:spring推荐使用transactionTemplate,在开发当中用的比较多。
声明式事务:将我们从复杂的事务中解脱出来,获取连接,关闭连接,事务提交,异常处理,回滚,spring都已经帮我们处理好了。声明式事务采用了aop面向切面编程,本质就是在目标方法前后进行拦截,在目标方法前创建或者插入一个事务,在目标方法后提交一个事务,或者回滚。
如何管理:
Spring主要是通过三个接口,由这三个接口共同管理完成。
1、PlatformTransactionManager: 事务管理器,主要是用于平台相关的管理,主要是有三个接口,getTransaction, commit, rollback.
2、TransactionDefinition: 事务定义信息,用来定义事务相关的属性,给事务管理器PlatformTransactionManager使用。主要有以下几个接口getIsolationLevel 获取事务隔离级别,getProgationBehavior获取传播行为,getTimeOut获取超时时间,isReadOnly是否只读,事务管理器可以通过这些返回值进行优化,这些事务的配置信息都可以通过配置文件进行配置
3、TransactionStatus: 事务具体运行状态--事务管理过程中,每个时间点,事务的状态信息。包含几个接口haveSavePoint是否包含一个保存点,isCompleted 返回事务是否完成或者提交,isNewTransaction判断当前事务是否是一个新事务。
声明式事务的优缺点:优点就是不需要在业务代码当中进行配置,只需要在配置文件中或者具体的方法上面添加注解,这种方式没有侵入性,便于操作,方便管理。缺点:声明式事务的粒度不够细,在具体的代码块上面如果想要添加事务,只能将其抽象成方法。
Spring循环注入原理
循环注入分为四种情况
1、构造方法循环依赖,A依赖B,B依赖C,C依赖A,这种方式的依赖无法解决,会直接报错抛出BeanCurrentlyCreationException,原因是,Spring在创建bean时,会将当前创建的bean放入到一个正在创建的ConcurrentHashMap当中,如果在创建bean的时候,发现已经在这个正在创建的hasMap当中就会抛出异常,对于已经创建完毕的bean,会将从这个正在创建的hashMap中移除。
2、通过setter方法进行依赖注入的,并且对象是单例模式,这种情况下不会报错。对象A通过无参的构造方法创建好一个对象,放在正在创建池,即hashMap当中,会将创建好的A暴露出来,然后进行setter注入B,然后容器通过无参的构造方法创建一个对象B,将其放在正在创建池的hashMap中,创建好的B也可以爆楼出来,再创建C,放入到正在构建池当中,通过暴露出来的A对象进行setter注入。然后再对A当中进行setter注入B。如果我们在将ClassPathXmlApplicationContext对象当中setAllowCircleReference设置成false,再调用refresh方法,那么即使为单例模式的循环依赖,也会抛出异常。
3、如果是setter方法注入,但是每个对象并不是单例而是prototype,那么还是会抛出BeanCurrentlyException,原因在于,prototype创建出来的bean并不会进行缓存,在构建C的时候,不能获取到一个暴露出来的对象A,因为就会抛出异常。
4、如果是工厂bean(即实现了FactoryBean接口的bean)和普通类型的bean之间存在循环依赖,那么在工厂bean的getObject方法中,需要初始化好普通bean,详细信息,论Spring中循环依赖的正确性与Bean注入的顺序关系
Spring当中自动装配的方式有哪些
1、No,不启动自动装配的方式
2、byName, 通过属性的名字来查找javaBean依赖的对象并为其注入,
3、byType:通过属性的类型查找javaBean依赖的对象并注入
4、constructor 同byType一样,也是通过类型查找进行注入,但是不是通过setter方法注入,而是通过构造方法注入
5、autodetect:在byType和constructor之间自动选择注入方式
6、default:由上级标签<beans>的default-autowire属性确定