zero's Blog

持续迭代

前言

Spring中用@Async注解标记的方法,称为异步方法,它会在调用方的当前线程之外的独立的线程中执行,其实就相当于我们自己new Thread(()-> System.out.println(“hello world !”))这样在另一个线程中去执行相应的业务逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// @Async 若把注解放在类上或者接口上,那么他所有的方法都会异步执行了~~~~(包括私有方法)
public interface HelloService {
Object hello();
}

@Service
public class HelloServiceImpl implements HelloService {

@Async // 注意此处加上了此注解
@Override
public Object hello() {
System.out.println("当前线程:" + Thread.currentThread().getName());
return "service hello";
}
}

然后只需要在配置里,开启对异步的支持即可:

1
2
3
4
5
@Configuration
@EnableAsync // 开启异步注解的支持
public class RootConfig {

}

使用的是线程池SimpleAsyncTaskExecutor,这也是Spring默认给我们提供的线程池。

Read more »

要了解Spring MVC是怎么把@RequestMapping注解的方法以及类关联到相应的url上,首先需要看下AbstractHandlerMethodMapping

1
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {

  AbstractHandlerMethodMapping是一个InitializingBean,因此来看afterPropertiesSet()方法:

1
2
3
4
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
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
protected void initHandlerMethods() {
// …略
// 读取Spring容器中的所有beanNames
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));

for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// …略
}
// 判断这个bean是不是处理类
// 根据这个类是否使用了@Controller或@RequestMapping
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
Read more »

[toc]

一 请求数据记录

Spring Boot提供了一个内置的日志记录解决方案,通过 AbstractRequestLoggingFilter 可以记录请求的详细信息。

AbstractRequestLoggingFilter 有两个不同的实现类,我们常用的是 CommonsRequestLoggingFilter。

img

通过 CommonsRequestLoggingFilter 开发者可以自定义记录请求的参数、请求体、请求头和客户端信息。

启用方式很简单,加个配置就行了:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class RequestLoggingConfig {
@Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true); // 是否记录请求body内容
filter.setIncludeHeaders(true); // 是否记录请求header信息
filter.setIncludeClientInfo(true); // 是否记录请求客户端信息
filter.setAfterMessagePrefix("REQUEST DATA-"); // 设置前缀
return filter;
}
}

接下来需要配置日志级别为 DEBUG,就可以详细记录请求信息:

1
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG

img

Read more »

实现 ApplicationListener 接口,输出所有事件。

当以 @Component 方式配置时

事件触发顺序如下:

  1. ApplicationListener#ContextRefreshedEvent
  2. ApplicationListener#ServletWebServerInitializedEvent
  3. ApplicationListener#ApplicationStartedEvent
  4. ApplicationListener#ApplicationReadyEvent
  5. ApplicationListener#ContextClosedEvent

当通过 /META-INF/spring.factories 配置时

配置内容如下:

1
org.springframework.context.ApplicationListener=com.github.abel533.event.ApplicationListenerImpl

此时输出的事件顺序如下:

  1. ApplicationListener#ApplicationStartingEvent

  2. ApplicationListener#ApplicationEnvironmentPreparedEvent

  3. ApplicationListener#ApplicationContextInitializedEvent

  4. ApplicationListener#ApplicationPreparedEvent

Read more »

在GitHub上看到一个不错的开源项目:Spring Startup Analyzer

从项目名称中就大概能猜到,这是一个分析Spring应用启动过程的工具。Spring Startup Analyzer通过采集Spring应用启动过程的数据,进而生成一个交互式的分析报告,帮助用户发现Spring应用启动慢的位置。同时,Spring Startup Analyzer还提供了Spring Bean异步初始化的工具,来帮助开发者加快Spring应用的启动时间。

下面一起来看看其提供的强大功能。

Read more »

[toc]

1.使用BeanFactoryPostProcessor

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
@Component
public class ConstomBeadFactoryPostProcessor implements BeanFactoryPostProcessor {

private Logger log = LoggerFactory.getLogger(ConstomBeadFactoryPostProcessor.class);

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("demonBean");

/**
* 属性注入方式,
* * @see #AUTOWIRE_NO 0,默认 @Autowired
* * @see #AUTOWIRE_BY_NAME setter方法
* * @see #AUTOWIRE_BY_TYPE
* * @see #AUTOWIRE_CONSTRUCTOR 构造方法注入
* * @see #AUTOWIRE_AUTODETECT
*/
int autowireMode = genericBeanDefinition.getAutowireMode();
log.debug("{}, autowireMode={}", genericBeanDefinition.getBeanClassName(), autowireMode);


/**
* 修改 bean的 构造方式
*/
GenericBeanDefinition personBeanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("person");
ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0,"zero");
personBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);

// log.debug("beanFactory={}", beanFactory);

}
}
Read more »

表单类型参数

有时候需要将前台传来一些特定格式的数据对象转化成特定的Java对象,这个时候类型转换器就派上用场了。这里简单介绍使用比较简单的Converter接口。Converter是Spring 3.0后的一个函数式接口,只有一个方法,将source转化成target。

首先需要定义自己的转换器,需要实现Converter<S,T>接口,convert就是具体的转换方法。

一般推荐使用ConditionalGenericConverter

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
import java.util.Set;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.stereotype.Component;

public class CustomConditionalConverter implements ConditionalGenericConverter {

@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return targetType.hasAnnotation(Key.class);
}

@Override
public Set<ConvertiblePair> getConvertibleTypes() {
// getConvertibleTypes方法返回可转换的源类型和目标类型的配对,
// 如果只关心,字符串类型的转换。
// return Collections.singleton(new ConvertiblePair(String.class, String.class));

// 如果全部都关注
return null;
}

@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Key annotation = targetType.getAnnotation(Key.class);
try {
return annotation.using().newInstance().convert(source);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

然后需要将自定义的转换器进行注册:

1
2
3
4
5
6
7
8
@Configuration
public class CustomWebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new CustomConditionalConverter());
}
}

Read more »

转载自:https://blog.csdn.net/doctor_who2004/article/details/79184230

  @Conditional注解可以根据任何环境条件来注册bean,是否注册bean实例的条件有如下几个:

  • 在classpath路径中是否存在某个特定的类
  • 在ApplicationContext中是否还没注册过一个特定类型的bean
  • 是否在某路径下存在某文件
  • 是否在配置文件中配置了某特定的属性
  • 是否存在某特定的系统环境变量
Read more »

  1. @Configuration 注解是 Spring 组件注解的一种,通过普通的 Bean 扫描也可以扫描到 @Configuration。
  2. @Configuration 注解注册到 Spring 中的 Bean 是一个 CGLIB 代理的 Bean,而不是原始 Bean,这一点和 @Component 不一样,@Component 注册到 Spring 容器中的还是原始 Bean。
Read more »

转载自:https://www.cnblogs.com/aspirant/p/9082858.html


  BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。
  在Spring中,所有的bean都是由BeanFactory(也就是IOC容器)来进行管理的。如XMLBeanFactory就是一种典型的BeanFactory。常用的ApplicationContext接口也是由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先。
  对FactoryBean而言,这个bean不是简单的bean,而是一个能生产或者装饰对象生成的工厂bean,它为IOC容器中bean的实现提供了更加灵活的方式,可以在getObject()方法中灵活配置。

Read more »
0%