18.7.22
属性注入和构造器注入区别
Spring也同时支持两种依赖注入方式:设值注入和构造注入。 这两种依赖注入的方式,并没有绝对的好坏,只是适应的场景有所不同。相比之下,设值注入有如下优点:
1、设值注入需要该Bean包含这些属性的setter方法
2、与传统的JavaBean的写法更相似,程序开发人员更容易理解、接收。通过setter方法设定依赖关系显得更加只管。
3、对于复杂的依赖关系,如果采用构造注入,会导致构造器国语臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化器依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题
4、尤其是在某些属性可选的情况况下,多参数的构造器显得更加笨重
构造注入也不是绝对不如设值注入,在某些特定的场景下,构造注入比设值注入更加优秀。构造注入有以下优势:
1、构造注入需要该Bean包含带有这些属性的构造器
2、构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。例如,组件中其他依赖关系的注入,常常要依赖于DataSrouce的注入。采用构造注入,可以在代码中清晰的决定注入顺序。
3、对于依赖关系无需变化的Bean,构造注入更有用处。因为没有Setter方法,所有的依赖关系全部在构造器内设定。因此,无需担心后续的代码对依赖关系产生破坏。
4、依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。
建议:采用以设值注入为主,构造注入为辅的注入策略。对于依赖关系无需变化的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用设值注入。
参考:https://blog.csdn.net/sdx1237/article/details/59173172
————————————
18.6.7
1、过滤器
过滤器依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
在web.xml中配置过滤器
<filter>
<description>字符集过滤器</description>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
以上是一个已有过滤器,配置使用。
还可以自定义过滤器,实现Filter接口,实现三个方法:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
public void destroy()
public void init(FilterConfig arg0) throws ServletException
doFilter最好需要调用filterChain.doFilter(req, res);继续过滤链。
在spring中,filter都默认继承OncePerRequestFilte,OncePerRequestFilter顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。
源码里其实是对请求和回应进行过滤了。
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
}
在servlet-2.3中,Filter会过滤一切请求,包括服务器内部使用forward转发请求和<%@ include file="/index.jsp"%>的情况。
到了servlet-2.4中Filter默认下只拦截外部提交的请求,forward和include这些内部转发都不会被过滤,但是有时候我们需要 forward的时候也用到Filter。
因此,为了兼容各种不同的运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。
Filter有一系列的抽象或实现,见https://blog.csdn.net/liangxw1/article/details/51095484
参考:https://blog.csdn.net/MissEel/article/details/79351231
http://ully.iteye.com/blog/1334925
2、监听器:
它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。
它是实现了javax.servlet.ServletContextListener 接口的服务器端程序。
2 <listener>
3 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
4 </listener>
——
2 <listener>
3 <listener-class>com.kingdee.opensys.common.util.ReadPropertiesListener</listener-class>
4 </listener>
——
public class ReadPropertiesListener implements ServletContextListener{
5
6 public void contextDestroyed(ServletContextEvent sce) {
7 // TODO Auto-generated method stub
8
9 }
10
11 public void contextInitialized(ServletContextEvent sce) {
12 // TODO Auto-generated method stub
13 String path = sce.getServletContext().getRealPath("/WEB-INF/config/common.properties");
14 PropertiesUtils.init(path);
15 }
16
17 }
——
2 <context-param>
3 <param-name>log4jConfigLocation</param-name>
4 <param-value>/WEB-INF/classes/config/log4.properties</param-value>
5 </context-param>
6
7 <listener>
8 <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
9 </listener>
参考:https://www.cnblogs.com/youzhongmin/p/6940418.html
3、过滤器与拦截器的区别
1)过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
testFilter1
testFilter2
BaseInterceptor
TestInterceptor
参考:https://blog.csdn.net/xiaoyaotan_111/article/details/53817918
——————————
18.5.30
1、@RequestParam和@PathVariable 区别。
(1)@RequestParam针对URI如下格式的:
url = “{ctx}/main/mm/am/edit?Id={Id}&name={name}” 一定要有键值对 可以这么用: @RequestMapping("/edit") public String edit(Model model, @RequestParam Map paramMap ) {long id = Long.parseLong(paramMap.get("id").toString());} 也可以这么用: User printUser(@RequestParam(value = "id", required = false, defaultValue = "0") int id){} (2)@PathVariable针对URI如下格式的: url = “{ctx}/main/mm/am/edit/{Id}/{name}”
没有键值对
只能这么用:
RequestMapping("/edit/{id}/{name}")
public String edit(Model model, @PathVariable long id,@PathVariable String name) {}
参考:https://www.cnblogs.com/helloworld-hyyx/p/5295514.html
https://www.cnblogs.com/hq233/p/7146264.html
——————————
18.5.14
1、spring拦截器
Java里的拦截器是动态拦截action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。
实现HandlerInterceptor接口,实现几个方法,配置到<Bean>或者加个注解,就实现了一个拦截器。
在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。
前者代表对所有的请求进行拦截,而后者带有mvc:interceptor则代表有着更精细的控制。
注册全部url到拦截器:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
An example of registering an interceptor limited to a specific URL path:
注册指定url到拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/" />
<mvc:exclude-mapping path="/static/" /> //判处拦截的url
<bean class="拦截器java代码路径" />
</mvc:interceptor>
</mvc:interceptors>
preHandle,SpringMVC中的Interceptor拦截器是链式的,可以同时存在多个Interceptor,
然后SpringMVC会根据声明的前后顺序一个接一个的执行,
而且所有的Interceptor中的preHandle方法都会在Controller方法调用之前调用。
SpringMVC的这种Interceptor链式结构也是可以进行中断的,
这种中断方式是令preHandle的返回值为false,当preHandle的返回值为false的时候整个请求就结束了。
postHandle,这个方法只会在当前这个Interceptor的preHandle方法返回值为true的时候才会执行。
postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之 后, 也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操作。这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用,这跟Struts2里面的拦截器的执行过程有点像,只是Struts2里面的intercept方法中要手动的调用ActionInvocation的invoke方法,Struts2中调用ActionInvocation的invoke方法就是调用下一个Interceptor或者是调用action,然后要在Interceptor之前调用的内容都写在调用invoke之前,要在Interceptor之后调用的内容都写在调用invoke方法之后。
afterCompletion,该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行, 这个方法的主要作用是用于清理资源的。
执行顺序:
===========HandlerInterceptor1 preHandle
===========HandlerInterceptor2 preHandle
===========TestController
===========HandlerInterceptor2 postHandle
===========HandlerInterceptor1 postHandle
==========test.jsp
===========HandlerInterceptor2 afterCompletion
===========HandlerInterceptor1 afterCompletion
对于以上三个方法的参数Object handler,相当于响应的处理器(如Controller实现),
可能的使用如下:
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
System.out.println("[a-preHandle]>>>请求控制器名称:" + handlerMethod.getBean().getClass().getName());
System.out.println("[a-preHandle]>>>请求方法名称:" + handlerMethod.getMethod().getName());
}
常见应用场景
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。
spring提供了一个空的HandlerInterceptorAdapter实现了HandlerInterceptor。就不用必须实现三个方法了。
参考:https://www.sohu.com/a/128772280_523754
https://www.cnblogs.com/super-chao/p/6496428.html
https://blog.csdn.net/tong_xinglong/article/details/52035131
https://www.cnblogs.com/nizuimeiabc1/p/7717531.html
https://zhidao.baidu.com/question/629424828579600284.html
http://jinnianshilongnian.iteye.com/blog/1670856/
http://jinnianshilongnian.iteye.com/blog/1670856
2、web.xml中的contextConfigLocation
在web.xml中通过contextConfigLocation配置spring,
contextConfigLocation参数定义了要装入的 Spring 配置文件。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
如果没有指定路径,默认会去/WEB-INF/下加载applicationContext.xml。
如果想装入多个配置文件,可以在 <param-value>标记中用逗号作分隔符。
在web.xml里配置Listener
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener listener-class >
</listener>
参考:https://blog.csdn.net/zhangliao613/article/details/6289114
3、ContextLoaderListener
ContextLoaderListener是spring的核心监听器,它的作用是:在启动Web容器时,自动装配contextConfigLocation指定的xml配置信息。
因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
参考并继续学习:https://blog.csdn.net/qq924862077/article/details/52769754
https://blog.csdn.net/MrZhangXL/article/details/78587426
https://www.cnblogs.com/hello-yao-ge/p/5891435.html
https://blog.csdn.net/liangxw1/article/details/51037533
https://www.cnblogs.com/quan-coder/p/8436471.html
https://www.cnblogs.com/Zyf2016/p/6374160.html
——————————
17.12.19
1、@Autowired与@Resource区别
前者属于基于类型装配。如果需要安装名称装配,需要配合使用@Autowired()@Qualifier("baseDao")
后者属于J2EE的注解。默认安照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。@Resource(name="baseDao")
再加一条:@Resource注解是由JDK提供,而@Autowired是由Spring提供。
java为我们提供了 javax.annotation.Resource这个注解。
spring框架提供了org.springframework.beans.factory.annotation.Autowired。
@Autowire 默认按照类型装配,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果我们想使用按照名称装配,可 以结合@Qualifier注解一起使用;
@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属 性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找 依赖对象.
2、@Component,@Service,@Controller,@Repository的关系
答:在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的。
但是从注释类的命名上,很容易看出这 3 个注解分别和持久层、业务层和控制层(Web 层)相对应。
也许 Spring 将在以后的版本中为这三个注解添加特殊的功能。
如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller对分层中的类进行注释
而用 @Component 对那些比较中立的类进行注释。
@Service: 为所有的web服务类型使用,所有业务逻辑都在这里 换句话说,数据相关的计算和 all.This 注释,我们的用户不直接调用持久化方法,因此它使用这个注释调用这个方法。 请求 @Repository 为每个用户请求
@Repository: 对所有存储的过程数据库连接使用,这是应用程序的数据访问层,用于从数据库获取数据。 换句话说,将所有相关的数据库操作都由仓库完成。
@Component - 用组件构造型注释其他组件的( 例如REST资源类) 。
3、@Configuration与@Component区别
答:(1)、@Component注解的范围最广,所有类都可以注解。但是@Configuration是一个配置类。
(2)、@Configuration是Spring2.5提供的注解,用于将所标注的类加载到 Spring 环境中,需要搭配 component-scan 使用。Configuration 是 Spring 3.X 后提供的注解,用于取代 XML 来配置 Spring。
(3)、在@Component类中使用方法或字段时不会使用CGLIB增强(及不使用代理类:调用任何方法,使用任何变量,拿到的是原始对象,后面会有例子解释)。而在@Configuration类中使用方法或字段时则使用CGLIB创造协作对象(及使用代理:拿到的是代理对象);当调用@Bean注解的方法时它不是普通的Java语义,而是从容器中拿到由Spring生命周期管理、被Spring代理甚至依赖于其他Bean的对象引用。在@Component中调用@Bean注解的方法和字段则是普通的Java语义,不经过CGLIB处理。
参考:http://blog.csdn.net/ttjxtjx/article/details/49866011
http://blog.csdn.net/isea533/article/details/78072133?locationNum=7&fps=1
4、注解分两类:一类用于将Bean装配。比如@Autowired,@Resource。
一类用于注册Bean,@Component , @Repository , @ Controller , @Service ,
@Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired ,
@Resource配合到一起,把对象、属性、方法完美组装。
参考:https://www.cnblogs.com/java-synchronized/p/6576507.html
5、@Bean 注解产生Bean的方法。因此@Bean都在方法上,说明该方法将产生一个Bean,然后交给Spring管理。
@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。
6、@Configration注解在类上。@Bean注解在方法上。怎么回事?
@Configration注解的类会被作为Bean交给Spring管理。
@Bean注解的方法会生成Bean交给Spring管理。他们两个是不矛盾的。
@Configuration可理解为用spring的时候xml里面的<beans>标签
@Bean可理解为用spring的时候xml里面的<bean>标签
参考:https://blog.csdn.net/u012260707/article/details/52021265
————————————
17.12.7
ICO很简单,写好类,在配置文件中写好<bean>,然后使用Java反射机制通过<bean>中的名字创建实例,然后注入到需要的实例中。
注解则是进一步对该过程进行封装,无需写配置文件,直接扫描注解进行如上步骤。
有时间来把两种方式的简单实现写一下。