验证中...
gistfile1.txt
Raw Copy
Spring中Resource注解
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入。@Resource有两个重要的属性name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
Spring IoC实现(解耦)
BeanFacotry是spring中较原始的Factory,XMLBeanFactory就是典型的BeanFactory;
原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等;
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能;ApplicationContext以更向面向框架的方式工作以及对上下文进行分层和实现继承;
IoC容器BeanFactory(基本)和ApplicationContext(高级)两个都是接口,需要具体实现类(常用WebApplicationContext);
BeanDefinition是spring IoC容器存储的基本数据结构(xml配置文件等),是对pojo的抽象。BeanFactory接口(GenericBeanDefinition实现类)有getBean方法(最主要的方法,依赖注入的入口);isSingleton;isPrototype;isTypeMatch(是否是指定的class类型);getType(获取class类型);getAliases(获取别名)。
回调:A调用B,但B中有A的引用,B中再调用A,可以传入B中处理好的参数
IoC容器初始化
在配置文件中配置ContextLoaderListener监听器,并指定spring配置文件位置;
Servlet容器启动(tomcat)会为应用创建一个“全局上下文环境”ServletContext;
容器调用web.xml中配置的contextLoaderListener,初始化WebApplicationContext上下文环境(即IoC容器,默认XmlWebApplicationContext),加载context-param指定的配置文件信息到IoC容器中。WebApplicationContext在ServletContext中以键值对的形式保存,此时开始IoC容器的初始化。
IoC容器的初始化由refresh()方法启动(这个方法在IoC具体实现类的构造函数中),启动包括BeanDefinition的Resouce定位(获取资源位置的Resource对象)、载入(解析xml配置文件,获取各个Element信息)和注册(将BeanDefinition放入HashMap中)三个基本过程。
Resource定位
构造IoC容器时,需要指定BeanDefinition的信息来源(如从xml文件中来),而这个信息来源需要封装成spring中的Resource类。Resource是Spring用来封装I/O操作的类。Resource是一个接口,具体实现类如ClassPathResource。通过配置文件指定的文件位置完成BeanDefinition的定位,但具体的数据还没开始读入。Resource只是BeanDefinition位置的封装,具体操作由ResourceLoader完成,这个过程即找到BeanDefinition的位置,为其载入创造I/O操作的条件。
1.构造函数调用refresh(),该方法在synchronized修饰的同步代码块中,保证不能有多个线程初始化。
2.refresh()先调用createBeanFactory()创建容器
3.refresh()再调用loadBeanDefinitions(BeanFactory)方法
4.loadBeanDefinitions()先调用ResourceLoader得到Resource[]数组(定位)
5.loadBeanDefinitions()再调用Reader读取器(如XMLBeanDefinitionReader)读取Resource[]中资源(完成I/O操作,即开始载入),利用回调把结果传入之前建立的BeanFactory中;很多不同的类都有loadBeanDefinitions方法,它们的功能也是不同的。
BeanDefinition的载入
把用户定义好的Bean表示成IoC容器内部的数据结构(即BeanDefinition);
BeanDefinition的载入分两部分,首先调用XML解析器得到document对象,但这些document对象没有按照spring的bean规则进行解析,接下来按照spring规则进行解析:
1.在Reader读取器(如XMLBeanDefinitionReader的loadBeanDefinitions方法)中调用documentLoader(XML解析器)中的方法,获得document对象;
2.在Reader读取器(如XMLBeanDefinitionReader的loadBeanDefinitions方法)再调用processBeanDefinition(传入document的element);
3.processBeanDefinition (element,BeanDefinition),
此方法调用parseBeanDefinitionElement()方法,解析具体的元素标签(如<bean>、<name>、<id>等),将解析得到的结果设置到BeanDefinitionHolder中(BeanDefinitionHolder是BeanDefinition对象的封装类,封装了BeanDefinition、bean的名字等,用它来完成向IoC容器注册);
经过对document逐层解析,在XML中定义的BeanDefinition就被载入到了IoC容器中,但是重要的依赖注入在这个时候还没有发生,现在IoC容器中BeanDefinition存在的还只是一些静态的配置信息。
BeanDefinition的注册
BeanDefinition数据在IoC容器中通过ConcurrentHashMap来保持和维护,beanName为key,beanDefinition为value。
在processBeanDefinition()方法中调用registerBeanDefinition(BeanDefinitionHolder)开始注册;map.put(beanName,BeanDefinition)和registerBeanDefinition中都需要使用synchronized同步代码块来保证数据一致性,以上过程都是在Reader读取器类中完成的。
IoC容器的依赖注入
依赖注入的过程是用户首次向IoC容器索要Bean时触发的(BeanFactory.getBean(name)),当然也有例外,也可以在BeanDefinition信息中通过控制lazy-init属性来让容器完成对Bean的预实例化(在初始化过程中完成,即在refresh()(初始化的入口)时调用getBean())。通过依赖注入生成实例。
1.getBean()方法中,首先判断是否已经创建且为单例,如果是则不创建;然后根据Bean的名字获取BeanDefinition,当前取不到就到双亲BeanFactory中取,如果还取不到就顺着双亲链向上查找。
2.取到BeanDefinition后,获取当前Bean所依赖的所有Bean,并递归调用getBean。
3.通过createBean创建Bean的实例,最后返回Bean。
4.在createBean()中,调用createBeanInstance()创建Bean(默认使用CGLIB常用的字节码生成器类库或使用JVM的反射);
5.createBean()中,再调用populateBean()方法,将当前Bean的依赖注入,通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。
Bean的其它
Bean的预实例化:设置了lazy-init属性,在refresh方法中就会调用getBean;
Bean对IoC容器的感知:实现ApplicationContextAware接口,可以在Bean中得到Bean所在的应用上下文ApplicationContext,从而直接在Bean中使用(如getBean);在IoC对Bean初始化时会对Bean类型判断,如果是ApplicationContextAware的类型,那么IoC会调用其setApplicationContext方法,将ApplicationContext设置进去。
注解:扫描spring容器中指定包,找到包中加注解的类,然后将该类纳入spring容器
Spring依赖注入方式
1.Set注入
2.构造器注入
3.静态工厂的方法注入
4.实例工厂的方法注入
通过Spring创建的对象默认是单例的,如果需要创建多实例对象可以在<bean>标签后面添加一个属性:<bean name="..." class="..." scope="prototype">
通过IoC容器实现的依赖反转,把依赖关系的管理从Java对象中解放出来,交给了IoC容器来完成,从而完成了对象之间的关系解耦,利用cglib或反射实现。
Spring AOP实现
Aspect Oriented Programming面向切面编程,是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其它类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。切面简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。将重复的代码抽取出来(不同的模块),在需要时统一调用,可以不同的模块按不同的顺序调用,解耦。
AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理、缓存、对象池管理以及日志记录。
连接点:类里面可以被增强的方法;
切入点:实际增强的方法;
通知/增强:增强的逻辑,例如日志功能;
切面:把增强应用到具体方法上面,把增强用到切入点的过程,此过程称为切面;
advice:切面增强设计;
pointcut:切入点
advisor(通知器):把advice和pointcut结合起来,可以定义应该使用哪个advice并在哪个pointcut使用;advisor中有advice和pointcut两个属性;pointcut使用饿汉单例模式(static final);
Spring AOP实现中,使用的核心技术是动态代理,而这种动态代理实际上是JDK的特性(Proxy模式,在Proxy的调用过程中,如果客户调用Proxy的request方法,先调用Proxy的前处理方法,再调用目标对象的request方法,再调用Proxy的后处理方法(通过反射、拦截器链等实现));
实现:
ProxyFactoryBean是AOP中最重要的一个类,在xml文件中配置,并放入IoC中(<bean>),对于ProxyFactoryBean把需要对target目标对象增加的增强处理都通过getObject()方法封装了(工厂模式);以getObject方法作为入口,Spring AOP调用AopProxyFactory作为AopProxy代理对象的生产工厂,由它来负责产生相应的AopProxy代理对象(默认使用JDK的Proxy,或CGLIB)。
在AopProxy代理的接口方法被调用执行时(调用原对象的方法即调用代理对象的方法),首先会触发对这些方法调用进行拦截,这些拦截对目标调用的功能增强提供了工作空间,拦截过程在JDK的proxy代理对象中是通过invoke方法来完成的。在Spring AOP通过JDK的Proxy方法生成代理对象时,相关的拦截器(通知器链)已经配置到代理对象中了。
在InvocationHandler的invoke回调中,首先会根据配置来对拦截器是否与当前调用方法相匹配进行判断,如果匹配则相应的拦截器开始发挥作用;这个过程是个遍历的过程,它会遍历AopProxy代理对象中设置的拦截器链中的所有拦截器。拦截器逐一被调用,在拦截器都调用完后,才对目标对象方法调用。
通知器advisor在xml中配置,放在IoC容器中,拦截器,通知器等信息是存放在AdvisorSupport类中,通过getBean获取。在ProxyFactoryBean中获取IoC容器是实现了BeanFactoryAware接口。
为完成AOP应用需要的对目标对象增强,对于每种advice通知,spring设计了对应的AdviceAdapter通知适配器,这些通知适配器实现了advice通知对目标对象的不同增强方式(before、after等)。对于这些适配器,在AopProxy回调方法中有一个注册机制。完成注册后,拦截器链中运行的拦截器已经是经过适配的拦截器(实际上是通知器)。
如果是适配器支持的adapter.supportsAdvice(advice)(advice根据配置文件有before、after等类型),就将生成的包装后的拦截器放入拦截器链,如MethodBeforeAdviceAdapter,会产生MethodBeforeAdviceInterceptor,这个包装后的拦截器会先调用advice.before方法,在继续遍历拦截器链(methodInvocation.proceed());如果是after类型,就先继续遍历拦截器链(methodInvocation.proceed()),再调用after方法。Throws是通过catch中捕获异常实现的。相当于拦截器链中有很多adapter包装后的拦截器,依次遍历每个拦截器,调用其方法,从而实现了增强。电源适配器,它是用于电流变换(整流)的设备;适配器的存在是为了将已存在的东西(接口)转换成能被利用的,适合需要的接口。
Spring MVC实现
在启动过程中,spring会使用默认的WebApplicationContext实现作为IoC容器;这个默认使用的IoC容器就是XMLWebApplicationContext;对于spring承载的web应用而言,可以指定在web应用程序启动时载入IoC容器(WebApplicationContext);这个功能是由ContextLoaderListener这样的类来完成的,它是在web容器中配置的监听器(配置在web.xml中);这个ContextLoader就像spring应用程序在web容器的启动器,该IoC容器会被存储到SevletContext中。
在完成对ContextLoaderListener初始化后,web容器(tomcat)开始初始化DispatcherServlet,DispatcherServlet会建立自己的上下文来持有Spring MVC的Bean对象,在建立这个自己持有的IoC容器时,会从ServletContext中得到根上下文(WebApplicationContext)作为DispatcherServlet持有上下文的双亲上下文。有了这个根上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文保存到ServletContext中,供以后检索和使用。作为servlet,DispatcherServlet的启动与servlet启动过程是相联系的,servlet的init方法会被调用以进行初始化,接着会初始化DispatcherServlet持有的IoC容器。
Spring MVC的实现大致由以下几个步骤完成:
1.根据controller和HTTP请求之间的映射关系,将url和handle(controller)作为键值对放到HandlerMapping中的handlerMap(HashMap)中。
2.DispatcherServlet调用doDispatch方法,分发请求。
DispatcherServlet持有IoC容器,里面装有Controller、HandlerMapping、HandlerAdapter、ViewResolver等这些特殊的bean;
HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter将对实现了Controller接口的Bean进行适配,并且掉处理器的handleRequest方法进行功能处理;
ViewResolver:ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为jsp视图;
Spring MVC的运行流程
1. 用户向服务器发送请求,请求被Spring 前端控制器DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用处理器映射器HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的处理器适配器HandlerAdapter,如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法
4.提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller),在填充Handler的入参过程中,根据配置Spring将做些额外的工作:
HttpMessageConveter:将请求消息转换成对象,将对象转换为指定的响应信息;
数据转换:对请求消息进行数据转换,如String转换成Integer、Double等;
数据格式化:对请求消息进行数据格式化,如将字符串转换成格式化数字或日期等;
数据验证:验证数据的有效性(长度,格式等),将结果存储到BindingResult或Error中;
5.Handler执行完成后,向HandlerAdapter返回ModelAndView,HandlerAdapter向DispatcherServlet 返回ModelAndView对象;
6.根据返回的ModelAndView,选择适合的视图解析器ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7.ViewResolver 结合Model和View,来渲染视图
8.将渲染结果返回给客户端。
HandlerMapping组件负责的是定位请求处理器Handler,在HandlerMapping返回处理请求的Controller实例后,需要帮助定位具体请求方法的HandlerAdapter处理类,HandlerAdapter是处理器适配器,Spring MVC通过HandlerAdapter来实际调用处理函数。
Controller的线程安全问题
Action是多实例的,所以不存在线程安全的问题;而Controller默认是单例的,效率高但是有可能存在线程安全问题;Controller是基于方法的,所以只要不使用类成员变量,方法中都是局部变量,所以不会出现线程安全问题;如果使用成员变量,可以使用Threadlocal。
Spring的事务
使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。
编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现。
在xml中配置transactionManager这个bean,在DAO中方法上加@Transactional注解(可以设置事务隔离级别),从而完成声明式事务。
Spring 事务实现
声明式事务处理完全可以看做是具体的Spring AOP应用;
声明式事务处理的大致过程:在为事务处理配置好AOP的基础设施(比如对应的Proxy代理对象和事务处理Interceptor拦截器对象)之后,首先需要完成对这些事务属性配置的读取,这些属性的读取处理是在TransactionInterceptor中实现的;
TransactionInterceptor是使用AOP实现声明式事务处理的拦截器,封装了Spring对声明式事务处理实现的基本过程;TransactionAttributeSource和TransactionAttribute这两个类,它们封装了对声明式事务处理属性的识别,以及信息读入和配置;
TransactionInfo和TransactionStatus这两个对象,它们存放事务处理信息的主要数据对象,它们通过与线程的绑定(ThreadLocal)来实现事务的隔离性。TransactionInfo持有TransactionStatus,TransactionStatus掌管事务执行的详细信息,包括具体的事务对象、事务执行状态、事务设置状态。
在事务的创建、启动、提交和回滚过程中,都与TransactionStatus对象中的数据打交道。具体的事务处理是由事务处理器TransactionManager来完成。
Spring 中用到的设计模式
1.工厂模式:BeanFactory的getBean方法
2.单例模式:Spring中的Bean默认都是单例模式的,但没有通过构造器级别去实现,而是通过BeanFactory管理(重复的bean不会创建)
3.适配器模式:AOP中MethodBeforeAdviceAdapter、MethodAfterAdviceAdapter,将适配器支持的通知器包装成MethodBeforeAdviceAdapter等类型放入拦截器链中,MVC中handleAdapter
4.责任链模式:HandlerExecutionChain,AOP中InvocationHandler的invoke遍历拦截器
5.装饰器模式:BeanWrapper,包装了bean,提供bean更强大的操作功能,BeanWrapperImpl类是对BeanWrapper接口的默认实现,它包装了一个bean对象,缓存了bean的内省结果,并可以访问bean的属性、设置bean的属性值。
6.代理模式:Proxy在AOP中用到
7.观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
Spring中Observer模式常用的地方是listener的实现,如监听器ApplicationListener,事件ApplicationEvent。ApplicationContextAware使用观察者模式。
8.模板方法:如jdbcTemplate。Template Method模式一般是需要继承的,可以把变化的东西抽出来作为参数传入JdbcTemplate的方法中去。
9.策略模式:定义一系列算法后把它们封装起来,并且使它们可相互替换,本模式使得算法可独立于使用它的客户而变化,Spring在实例化对象的时候用到Strategy模式。
在SimpleInstantiationStrategy中,类图中提供了一个 Resouce 接口,这个接口就是 Spring 为资源访问所提供的策略接口,该接口下的大量实现类:UrlResource、ClassPathResource、 FileSystemResource都实现了该策略接口,用于实现不同的资源访问策略(classpath是项目编译后src目录,每次编译完在项目的web-inf 目录下有个classes的文件夹//url访问网络资源)。Arrays.sort排序传入不同的比较器也是策略模式
装饰器模式:能动态的新增或组合对象的行为;
代理模式:为其它对象提供一种代理以控制对这个对象的访问;
适配器模式:是对其它对象接口的转换行为,将原接口转换为目标接口,达到适配的效果;
外观模式:外观对象提供对子系统各元件功能的简化为共同层次的调用接口,起简化作用;
装饰模式是“新增行为”,代理模式是“控制访问行为”,适配器模式是"转换行为",外观模式是一种"简化行为"。
模板模式: 定义操作中的算法的骨架,而将步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。
1.抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
2.具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。
优点:
1.模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
2.子类实现算法的某些细节,有助于算法的扩展。
3.通过父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
Spring MVC与Struts
1.机制:spring mvc的入口是servlet,而struts2是filter。
2.性能:spring比struts快,spring mvc是基于方法的设计而struts是基于类,每次发请求都会实例action,每个action都会被注入属性;而spring基于方法,粒度更细。
spring mvc是方法级别的拦截,拦截到方法后根据参数上的注解,把request数据注入进去,在spring mvc中一个方法对应一个request上下文。而struts2框架是类级别的拦截,每次来了请求就创建一个Action,然后调用setter getter方法把request中的数据注入;struts2实际上是通过setter getter方法与request打交道的;struts2中一个Action对象对应一个request上下文。
3.springmvc可以进行单例开发,并且建议使用单例开发,struts2通过类的成员变量接收参数,无法使用单例,只能使用多例。
4.经过实际测试,struts2速度慢,在于使用struts标签,如果使用struts建议使用jstl。
过滤器和拦截器的区别
过滤器:理论上可过滤任何的内容
拦截器:只拦截action
Servlet和Action的区别
Servlet默认首次访问时候创建,创建一次,单实例对象
Action每次访问时候创建,创建多次,多实例对象
1. Spring的Java配置方式
最佳实践:
1、 应用的基本配置用xml,比如:数据源、资源文件等;
2、 业务开发用注解,比如:Service中注入bean等;
Java配置是Spring4.x推荐的配置方式,可以完全替代xml配置。
1.1. @Configuration 和 @Bean
Spring的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:
1、@Configuration 作用于类上,相当于一个xml配置文件;
2、@Bean 作用于方法上,相当于xml配置中的<bean>;
1.1.1. 编写测试方法用于启动Spring容器
// 通过Java配置来实例化Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 在Spring容器中获取Bean对象
UserService userService = context.getBean(UserService.class);
// 相关方法调用后销毁该容器
context.destroy();
1.1.2. 读取外部的资源配置文件
通过@PropertySource可以指定读取的配置文件,通过@Value注解获取值,具体用法:
@Configuration
// 通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = "XXX") //配置扫描包
@PropertySource(value= {"classpath:jdbc.properties"})
public class SpringConfig {
@Value("${jdbc.url}")
private String jdbcUrl;
@Bean // 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
public UserDAO getUserDAO(){
return new UserDAO();
}
}
思考:
1、 如何配置多个配置文件?
@PropertySource(value= {"classpath:XX1",”classpath:XX2”})
2、 如果配置的配置文件不存在会怎么样?
@PropertySource(value= {"classpath:XX1"},ignoreResourceNotFound=true)
1.1.3. 配置数据库连接池
参考xml配置改造成java配置方式:
@Bean(destroyMethod = "close")
public DataSource dataSource() {
BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
boneCPDataSource.setXXX(jdbcUsername);
return boneCPDataSource;
}
思考: 如何使用该DataSource对象?
2. Spring Boot
2.1. 什么是Spring Boot
先编译后运行=》静态语言
动态语言=》js等
开发效率低=》技术的整合比较麻烦
2.2. 快速入门
2.2.1. 设置spring boot的parent
Spring boot的项目必须要将parent设置为spring boot的parent,该parent包含了大量默认的配置。
2.2.2. 添加Spring boot的插件
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
2.2.3. 编写第一个Spring Boot的应用
@Controller
@SpringBootApplication
@Configuration
public class HelloApplication {
@RequestMapping("hello")
@ResponseBody
public String hello(){
return "hello world!";
}
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
代码说明:
1、@SpringBootApplication:Spring Boot项目的核心注解,主要目的是开启自动配置;
2、@Configuration:这是一个配置Spring的配置类;
3、@Controller:标明这是一个SpringMVC的Controller控制器;
4、main方法:在main方法中启动一个应用,即:这个应用的入口;
2.2.4. 启动应用
在Spring Boot项目中,启动的方式有两种,一种是直接run Java Application另外一种是通过Spring Boot的Maven插件运行【spring-boot:run】。
2.3. Spring Boot的核心
2.3.1. 入口类和@SpringBootApplication
Spring Boot的项目一般都会有*Application的入口类,入口类中会有main方法,这是一个标准的Java应用程序的入口方法。
@SpringBootApplication注解是Spring Boot的核心注解,它其实是一个组合注解:
该注解主要组合了以下注解:
1. @SpringBootConfiguration:这是Spring Boot项目的配置注解,这也是一个组合注解:
在Spring Boot项目中推荐使用@ SpringBootConfiguration替代@Configuration
2. @EnableAutoConfiguration:启用自动配置,该注解会使Spring Boot根据项目中依赖的jar包自动配置项目的配置项:
a) 如:添加了spring-boot-starter-web的依赖,项目中也就会引入SpringMVC的依赖,Spring Boot就会自动配置tomcat和SpringMVC
3. @ComponentScan:默认扫描@SpringBootApplication所在类的同级目录以及它的子目录。
2.3.2. 关闭自动配置
Spring Boot会根据项目中的jar包依赖,自动做出配置,Spring Boot支持的自动配置:
如果不需要Spring Boot自动配置,想关闭某一项的自动配置,该如何设置呢?
2.3.3. 自定义Banner
1. 打开网站:
2. http://patorjk.com/software/taag/#p=display&h=3&v=3&f=4Max&t=itcast%20Spring%20Boot
3. 拷贝生成的字符到一个文本文件中,并且将该文件命名为banner.txt
4. 将banner.txt拷贝到项目的resources目录中:
5. 重新启动程序,查看效果:
如果不想看到任何的banner,也是可以将其关闭的:
2.3.4. 全局配置文件
Spring Boot项目使用一个全局的配置文件application.properties或者是application.yml,在resources目录下或者类路径下的/config下,一般我们放到resources下。
2.3.5. Starter pom
2.3.6. Xml 配置文件
2.3.7. 日志
Spring Boot对各种日志框架都做了支持,可以通过配置来修改默认的日志的配置:
#设置日志级别
logging.level.org.springframework=DEBUG
格式:
logging.level.*= # Log levels severity mapping. For instance `logging.level.org.springframework=DEBUG`
2.4. Spring Boot的自动配置的原理
Spring Boot在进行SpringApplication对象实例化时会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器。
2.4.1. Maven下载源码
通过 dependency:sources 该命令可以下载该项目中所有的依赖的包的源码。
2.4.2. 源码分析
org.springframework.boot.SpringApplication:initialize
org.springframework.core.io.support.SpringFactoriesLoader:loadFactoryName
2.4.3. Spring.factories文件
2.4.4. 举例:Redis的自动配置
从上述的Spring.factories配置文件中可以看出Redis的自动配置是:
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,内容:
2.4.5. 条件注解
3. Spring Boot的web开发
Web开发的自动配置类:
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration
3.1. 自动配置的ViewResolver
视图的配置mvcProperties对象中:
org.springframework.boot.autoconfigure.web.WebMvcProperties.View
3.2. 自动配置静态资源
3.2.1. 进入规则为 /
如果进入SpringMVC的规则为/时,Spring Boot的默认静态资源的路径为:
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
3.2.2. 进入规则为*.xxx 或者不指定静态文件路径时
将静态资源放置到webapp下的static目录中即可通过地址访问:
3.3. 自定义消息转化器
自定义消息转化器,只需要在@Configuration的类中添加消息转化器的@bean加入到Spring容器,就会被Spring Boot自动加入到容器中。
@Bean
public StringHttpMessageConverter stringHttpMessageConverter(){
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
默认配置:
3.4. 自定义SpringMVC的配置
自已配置SpringMVC而不是采用默认,增加拦截器,通过继承WebMvcConfigurerAdapter后重写父类中的方法进行扩展。
@Configuration //申明这是一个配置
public class MySrpingMVCConfig extends WebMvcConfigurerAdapter{
// 自定义拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
HandlerInterceptor handlerInterceptor = new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("自定义拦截器............");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
}
};
registry.addInterceptor(handlerInterceptor).addPathPatterns("/**");
}
// 自定义消息转化器的第二种方法
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
converters.add(converter);
}
}
3.4.1. 设置Mybatis和Spring Boot整合
@Configuration
public class MyBatisConfig {
@Bean
@ConditionalOnMissingBean
//当容器里没有指定的Bean的情况下创建该对象
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置mybatis的主配置文件
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource mybatisConfigXml = resolver.getResource("classpath:mybatis/mybatis-config.xml");
sqlSessionFactoryBean.setConfigLocation(mybatisConfigXml);
// 设置别名包
sqlSessionFactoryBean.setTypeAliasesPackage("com.XXX.pojo");
return sqlSessionFactoryBean;
}
}
然后创建Mapper接口的扫描类MapperScannerConfig:
@Configuration
@AutoConfigureAfter(MyBatisConfig.class)
//保证在MyBatisConfig实例化之后再实例化该类
public class MapperScannerConfig {
// mapper接口的扫描器
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.XXX.mapper");
return mapperScannerConfigurer;
}
}
3.4.2. 设置事务管理
在Spring Boot中推荐使用@Transactional注解来申明事务。
当引入jdbc依赖之后,Spring Boot会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager,所以不需要任何额外配置就可以用@Transactional注解进行事务的使用。
3.4.3. 启动错误1
关键错误(丢失了web容器的工厂,也就是说我们并没有把它作为一个web应用来启动):
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
解决:
让Spring Boot来自动选择并且完成web的相关加载工作。
3.4.4. Slf4j日志警告
提示当前的项目中slf4j引入了2个,导致了jar冲突。
解决:
1、 删除自己引入到slf4j的依赖
3.4.5. 解决jsp访问404的问题
由于Spring boot使用的内嵌的tomcat,而内嵌的tamcat是不支持jsp页面的,所有需要导入额外的包才能解决。
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
4. 发布到独立的tomcat中运行
在开发阶段推荐使用内嵌的tomcat进行开发,生成环境则希望在独立的tomcat容器中运行,因为需要对tomcat做额外的优化,这时需要将工程打包成war包发进行发布。
4.1. 将spring-boot-starter-tomcat的范围设置为provided
设置为provided是在打包时会将该包排除,因为要放到独立的tomcat中运行,是不需要的。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
4.2. 修改代码,设置启动配置
需要集成SpringBootServletInitializer,然后重写configure,将Spring Boot的入口类设置进去,builder.sources(XXXApplication.class);

Comment list( 0 )

Sign in for post a comment

Help Search