zero's Blog

持续迭代

转载自:
  https://blog.csdn.net/ai_xiangjuan/article/details/79842385
  https://blog.csdn.net/ai_xiangjuan/article/details/79696639

  @InitBinder用于在@Controller中标注于方法上,表示为当前控制器注册一个属性编辑器,只对当前的Controller有效。@InitBinder标注的方法必须有一个参数WebDataBinder。所谓的属性编辑器可以理解就是帮助我们完成参数绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ResponseBody
@RequestMapping(value = "/test")
public String test(@RequestParam String name,@RequestParam Date date) throws Exception {
System.out.println(name);
System.out.println(date);
return name;
}

@InitBinder
public void initBinder(WebDataBinder binder){
binder.registerCustomEditor(String.class,
new StringTrimmerEditor(true));

binder.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));

}

  上面例子中,@InitBinder方法会帮助我们把String类型的参数先trim再绑定,而对于Date类型的参数会先格式化在绑定。例如当请求是/test?name=%20zero%20&date=2018-05-22时,会把zero绑定到name,再把时间串格式化为Date类型,再绑定到date。

Read more »

转载自:
  https://blog.csdn.net/nnsword/article/details/76260355
  https://blog.csdn.net/Rylan11/article/details/79433192

HandlerMethodArgumentResolver是用来为处理器解析参数的,主要用在HandlerMethod中,每个Resolver对应一种类型的参数。

1
2
3
4
5
6
7
8
9
10
public interface HandlerMethodArgumentResolver {
// 用于判断是否支持对某种参数的解析
boolean supportsParameter(MethodParameter parameter);

// 将请求中的参数值解析为某种对象
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}
Read more »

@ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:

  • 全局异常处理
  • 全局数据绑定
  • 全局数据预处理

全局异常处理
使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下:

1
2
3
4
5
6
7
8
9
10
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView customException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("myerror");
return mv;
}
}

在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法…,也可以直接向上面代码一样,在一个方法中处理所有的异常信息。

@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。

Read more »

转载自:
https://blog.csdn.net/qq_21387171/article/details/53876721
https://blog.csdn.net/catoop/article/details/50548009
http://blog.didispace.com/springbootproperties/

自定义属性与加载

  在application.properties可以自定义一些属性,然后通过@Value("${属性名}")注解来加载对应的配置属性。

参数间的引用

  在application.properties中的各个参数之间也可以直接引用来使用,就像下面的设置:

1
2
3
com.didispace.blog.name=程序猿DD
com.didispace.blog.title=Spring Boot教程
com.didispace.blog.desc=${com.didispace.blog.name}
Read more »

转载自:
  https://blog.csdn.net/jack__frost/article/details/71158139
  https://blog.csdn.net/qq924862077/article/details/53541678

  Spring MVC允许通过处理拦截拦截web请求,进行前置处理和后置处理。处理拦截是在Spring的web应用程序上下文中配置的,因此它们可以利用各种容器特性,并引用容器中声明的任何Bean。处理拦截是针对特殊的处理程序映射进行注册的,因此它只拦截通过这些处理程序映射的请求。
  HandlerInterceptor类似于Servlet开发中的过滤器Filter,用于处理器进行预处理和后处理。主要作用是拦截用户的请求并进行相应的处理,其他的作用比如通过它来进行权限验证,或者是来判断用户是否登陆,日志记录,或者限制时间点访问。
  除了这个之外,还可以用Spring的WebRequestInterceptor接口或者是继承实现了WebRequestInterceptor的类。

HandlerInterceptor接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface HandlerInterceptor {
// 在请求处理之前进行调用
// 只有返回true,才会继续执行后续的Interceptor和Controller
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;

// 在当前请求进行处理之后,也就是Controller方法调用之后执行
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;

// 该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;

}
Read more »

​ Servlet API 中提供了一个Filter接口,通过Filter可以实现在访问某个目标资源之前,对访问的请求和响应进行拦截。
  SpringBoot项目中可以通过两种方式来实现Filter的配置。首先看下自定义的Filter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UserFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("-----UserFilter init-------");
System.out.println(filterConfig);
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("-----UserFilter doFilter-------");
chain.doFilter(request, response);
}

@Override
public void destroy() {
System.out.println("----- UserFilter destroy-------");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class OtherFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("-----OtherFilter init-------");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("-----OtherFilter doFilter-------");

// Filter 只是链式处理,请求依然转发到目的地址
// 如果不想请求向下走可以不继续调用doFilter
chain.doFilter(request,response);
}

@Override
public void destroy() {
System.out.println("----- OtherFilter destroy-------");
}
}
Read more »

转载自:https://blog.csdn.net/ai_xiangjuan/article/details/79837712

ResponseBodyAdvice

主要作用是响应体写出之前做一些处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Order(1)  
@ControllerAdvice(basePackages = "com.github")
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Object> {

@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {
return methodParameter.getMethod().getReturnType().isAssignableFrom(User.class);
}

@Override
public Object beforeBodyWrite(
Object obj, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

User user = ((User)obj);
user.setName("---" + user.getName() + "---");
return user;
}
}

RequestBodyAdvice

请求增强。在读取请求body之前或者在body转换成对象之前可以做相应的增强。

[toc]

GC Cause

JVM 什么样的条件下选择进行 GC 操作,具体 Cause 的分类可以看一下 Hotspot 源码:src/share/vm/gc/shared/gcCause.hpp 和 src/share/vm/gc/shared/gcCause.cpp 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const char* GCCause::to_string(GCCause::Cause cause) {
switch (cause) {
case _java_lang_system_gc:
return "System.gc()";

case _full_gc_alot:
return "FullGCAlot";

case _scavenge_alot:
return "ScavengeAlot";

case _allocation_profiler:
return "Allocation Profiler";

case _jvmti_force_gc:
return "JvmtiEnv ForceGarbageCollection";

case _gc_locker:
return "GCLocker Initiated GC";

case _heap_inspection:
return "Heap Inspection Initiated GC";

case _heap_dump:
return "Heap Dump Initiated GC";

case _wb_young_gc:
return "WhiteBox Initiated Young GC";

case _wb_conc_mark:
return "WhiteBox Initiated Concurrent Mark";

case _wb_full_gc:
return "WhiteBox Initiated Full GC";

case _no_gc:
return "No GC";

case _allocation_failure:
return "Allocation Failure";

case _tenured_generation_full:
return "Tenured Generation Full";

case _metadata_GC_threshold:
return "Metadata GC Threshold";

case _metadata_GC_clear_soft_refs:
return "Metadata GC Clear Soft References";

case _cms_generation_full:
return "CMS Generation Full";

case _cms_initial_mark:
return "CMS Initial Mark";

case _cms_final_remark:
return "CMS Final Remark";

case _cms_concurrent_mark:
return "CMS Concurrent Mark";

case _old_generation_expanded_on_last_scavenge:
return "Old Generation Expanded On Last Scavenge";

case _old_generation_too_full_to_scavenge:
return "Old Generation Too Full To Scavenge";

case _adaptive_size_policy:
return "Ergonomics";

case _g1_inc_collection_pause:
return "G1 Evacuation Pause";

case _g1_humongous_allocation:
return "G1 Humongous Allocation";

case _dcmd_gc_run:
return "Diagnostic Command";

case _last_gc_cause:
return "ILLEGAL VALUE - last gc cause - ILLEGAL VALUE";

default:
return "unknown GCCause";
}
ShouldNotReachHere();
}

重点需要关注的几个GC Cause:

  • System.gc():手动触发GC操作。

  • CMS:CMS GC 在执行过程中的一些动作,重点关注 CMS Initial Mark 和 CMS Final Remark 两个 STW 阶段。

  • Promotion Failure:Old 区没有足够的空间分配给 Young 区晋升的对象(即使总可用内存足够大)。

  • Concurrent Mode Failure:CMS GC 运行期间,Old 区预留的空间不足以分配给新的对象,此时收集器会发生退化,严重影响 GC 性能,下面的一个案例即为这种场景。

  • GCLocker Initiated GC:如果线程执行在 JNI 临界区时,刚好需要进行 GC,此时 GC Locker 将会阻止 GC 的发生,同时阻止其他线程进入 JNI 临界区,直到最后一个线程退出临界区时触发一次 GC。

Read more »

  • 初始标记(CMS initial mark)只是标记一下GC Roots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。

  • 并发标记(CMS concurrent mark)进行GC Roots跟踪的过程,和用户线程一起工作,不需要暂停工作线程。

  • 重新标记(CMS remark)为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。

  • 并发清除(CMS concurrent sweep)清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程。

  • 重置(CMS concurrent reset) 清理数据结构,为下一个并发收集做准备.

Read more »

[toc]

如何处理跨代引用

​ 在垃圾回收的时候都是从Root开始搜索,这会先经过年轻代再到老年代,对于年轻代引用老年代的这种跨代不需要单独处理。但是老年代引用年轻代的会影响young gc,这种跨代需要处理。
​ 为了避免在回收年轻代的时候扫描整个老年代,需要记录老年代对年轻代的引用,young gc的时候只要扫描这个记录。

​ CMS和G1都用到了Card Table,但是用法不太一样。JVM将内存分成一个个固定大小的card,然后有一个专门的数据结构(即这里的Card Table)维护每个Card的状态,一个字节对应一个Card,有点像内存page的概念,只是page是硬件上的,Card Table是软件上的。当一个Card上的对象的引用发生变化的时候,就将这个Card对应的Card Table上的状态置为dirty,young gc的时候扫描状态是dirty的Card即可。这是基本的用法,CMS基本上就是这么使用。
​ G1在Card Table的基础上引入的Remembered Set(下面简称RSet)。每个region都会维护一个RSet,记录着引用到本region中的对象的其他region的Card。比如A对象在regionA,B对象在regionB,且B.f = A,则在regionA的RSet中需要记录B所在的Card的地址。这样的好处是可以对region进行单独回收,这要求RSet不只是维护老年代到年轻代的引用,也要维护这老年代到老年代的引用,对于跨代引用的每次只要扫描这个region的RSet上的Card即可。
​ 上面说过年轻代到老年代的引用不需要单独处理,这带来了很大的性能上的提升,因为年轻代的对象引用变化很大,如果都需要记录下来成本会很高。同时也说明只需要在老年代维护Card Table。

Read more »
0%