5-1:线程安全
private static AtomicInteger atomicCount = new AtomicInteger(0);
cas的实现 乐观锁
5-3:阻塞队列
5-4:copy-on-write
解决了线程安全问题
5-5:线程池
ThreadPoolExecutor
线程的五种运行状态
ThreadLocal
6-1:spring 常见的坑
spring的bean名称生成策略
对开头两个字母都大写的会特殊处理
直接返回不做任何处理
1、避免开头两个字母都是大写
2、主动指定名称
3、或者通过类型获取
6-3:@Autowired注解
package com.imooc.spring.escape.service;
import org.springframework.stereotype.Service;
/**
* <h1>Spring Bean 的默认名称生成策略</h1>
* */
@Service("qYImooc")
public class QYImooc {
public void print() {
System.out.println("QYImooc");
}
}
package com.imooc.spring.escape.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* <h1>学会使用 @Autowired 注解</h1>
* */
@Component
public class HowToUseAutowire {
@Autowired
private QYImooc imooc;
public void print() {
imooc.print();
}
}
package com.imooc.spring.escape.service;
import com.imooc.spring.escape.util.ApplicationUtils;
import com.imooc.spring.outer.Outer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestHowToUseAutowire {
@Test
public void firstTryTest() {
assert ApplicationUtils.getApplicationContext().containsBean("qYImooc");
HowToUseAutowire useAutowire = new HowToUseAutowire();
useAutowire.print();
}
@Test
public void secondTryTest() {
assert ApplicationUtils.getApplicationContext().containsBean("qYImooc");
HowToUseAutowire useAutowire = new HowToUseAutowire();
useAutowire.print();
}
@Test
public void thirdTryTest() {
assert ApplicationUtils.getApplicationContext().containsBean("qYImooc");
HowToUseAutowire useAutowire = ApplicationUtils.getBean(
HowToUseAutowire.class
);
useAutowire.print();
}
@Test
public void fourthTryTest() {
assert ApplicationUtils.getApplicationContext().containsBean("outer");
((Outer) ApplicationUtils.getBean("outer")).print();
}
}
6-4:上下文
解析配置文件,注册管理bean
第二种方式,使用listener和event监听获取应用上下文
@PostConstruct 会将bean初始化时执行
每次获取都是新的bean
spring使用三级缓存来解决循环依赖问题:
先让最底层的bean完成初始化,提前曝光,然后二级三级一起解决。
如果使用原型模式
就无法使用缓存,没法解决循环依赖问题
枚举的values方法会返回一个数组;
使用beanPostProcessor 简介代码
需求:解码器,不同的解码格式能调用不同的解码器
传统:使用if else不断的判断,不断的在需要的地方注入
优化:使用bean生命周期优化,只初始一次,并配置管理器进行统一管理
package com.imooc.spring.escape.bean_post_processor;
/**
* <h1>解码器接口定义</h1>
* */
public interface IDecoder {
VideoType type();
String decode(String data);
}
package com.imooc.spring.escape.bean_post_processor;
import org.springframework.stereotype.Service;
@Service
public class WMVDecoder implements IDecoder {
@Override
public VideoType type() {
return VideoType.WMV;
}
@Override
public String decode(String data) {
return this.type().getDesc() + ": " + data;
}
}
package com.imooc.spring.escape.bean_post_processor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AVIDecoder implements IDecoder, InitializingBean {
@Override
public VideoType type() {
return VideoType.AVI;
}
@Override
public String decode(String data) {
return this.type().getDesc() + ": " + data;
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("Init AVIDecoder In InitializingBean.");
}
}
package com.imooc.spring.escape.bean_post_processor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Service
public class DecoderManager implements BeanPostProcessor {
private static final Map<VideoType, IDecoder> videoTypeIndex = new HashMap<>(
VideoType.values().length
);
public String decode(VideoType type, String data) {
String result = null;
switch (type) {
case AVI:
result = videoTypeIndex.get(VideoType.AVI).decode(data);
break;
case WMV:
result = videoTypeIndex.get(VideoType.WMV).decode(data);
break;
default:
log.info("error");
}
return result;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (!(bean instanceof IDecoder)) {
return bean;
}
IDecoder decoder = (IDecoder) bean;
VideoType type = decoder.type();
if (videoTypeIndex.containsKey(type)) {
throw new IllegalStateException("重复注册");
}
log.info("Load Decoder {} for video type {}", decoder.getClass(),
type.getDesc());
videoTypeIndex.put(type, decoder);
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (!(bean instanceof IDecoder)) {
return bean;
}
log.info("BeanPostProcessor after init: {}", bean.getClass());
return null;
}
}
package com.imooc.spring.escape.bean_post_processor;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum VideoType {
AVI("AVI"),
WMV("WMV");
// TODO 定义更多的视频类型
private String desc;
}
测试用例:
package com.imooc.spring.escape.service;
import com.imooc.spring.escape.bean_post_processor.AVIDecoder;
import com.imooc.spring.escape.bean_post_processor.DecoderManager;
import com.imooc.spring.escape.bean_post_processor.ThirdPartyClass;
import com.imooc.spring.escape.bean_post_processor.VideoType;
import com.imooc.spring.escape.bean_post_processor.WMVDecoder;
import com.imooc.spring.escape.util.ApplicationUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Random;
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestBeanPostProcessor {
@Autowired
private AVIDecoder aviDecoder;
@Autowired
private WMVDecoder wmvDecoder;
@Test
public void testEasyUseDecoder() {
VideoType type = getRandomVideoType();
switch (type) {
case AVI:
log.info(aviDecoder.decode("video"));
break;
case WMV:
log.info(wmvDecoder.decode("video"));
break;
default:
log.info("error");
}
}
@Autowired
private DecoderManager decoderManager;
@Test
public void testUseDecoderManager() {
log.info(decoderManager.decode(getRandomVideoType(), "video"));
}
/**
* <h2>获取随机的 VideoType</h2>
* */
private VideoType getRandomVideoType() {
return VideoType.values()[new Random().nextInt(VideoType.values().length)];
}
@Test
public void testCheckBeanFactoryPostProcessor() {
ThirdPartyClass class01 = ApplicationUtils.getBean(ThirdPartyClass.class);
ThirdPartyClass class02 = ApplicationUtils.getBean(ThirdPartyClass.class);
System.out.println(class01.hashCode());
System.out.println(class02.hashCode());
}
}
声明式事务
标注在类上,public才生效
且优先级 类方法>类
隔离级别
可以主动标注让其可以 抛出 检查性异常
package com.imooc.spring.escape.transaction_lost;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@Service
public class SpringTransactionImpl implements ISpringTransaction {
@Autowired
private IdAndNameDao idAndNameDao;
@Override
@Transactional
public void CatchExceptionCanNotRollback() {
try {
idAndNameDao.save(new IdAndName("qinyi"));
// throw new RuntimeException();
} catch (Exception ex) {
ex.printStackTrace();
// 手动标记回滚
// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Override
@Transactional
public void NotRuntimeExceptionCanNotRollback() throws CustomException {
try {
idAndNameDao.save(new IdAndName("qinyi"));
throw new RuntimeException();
} catch (Exception ex) {
throw new CustomException(ex.getMessage());
}
}
@Override
@Transactional
public void RuntimeExceptionCanRollback() {
idAndNameDao.save(new IdAndName("qinyi"));
throw new RuntimeException();
}
@Override
@Transactional(rollbackFor = {CustomException.class})
public void AssignExceptionCanRollback() throws CustomException {
try {
idAndNameDao.save(new IdAndName("qinyi"));
throw new RuntimeException();
} catch (Exception ex) {
throw new CustomException(ex.getMessage());
}
}
@Transactional
public void anotherOneSaveMethod() {
idAndNameDao.save(new IdAndName("qinyi"));
throw new RuntimeException();
}
@Override
public void NonTransactionalCanNotRollback() {
anotherOneSaveMethod();
}
}
@Transactional 注解只能标注在 public上,在private和protected不生效,且数据库需要支持事务。
mvc
过滤器和拦截器
Filter的三个方法
init、doFilter、destroy
是一个链路,可以有多个
有点类似 数据结构 栈,先入后执行
HandlerInterceptor
preHandle 前置初始化操作,预处理,也可以做权限校验
postHandle 后置处理
afterCompletion 清理工作
编写过滤器 实现doFilter 接口
@WebFilter 接口
启动类写扫描包
package com.imooc.spring.escape.filter_and_interceptor;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "LogFilter")
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
long start = System.currentTimeMillis();
chain.doFilter(request, response);
log.info("LogFilter Print Log: {} -> {}",
((HttpServletRequest) request).getRequestURI(),
System.currentTimeMillis() - start);
}
@Override
public void destroy() {
}
}
filter是servlet规范;
interceptor是spring boot规范,是spring管理的bean可以用所有资源。
spring boot 优先级加载顺序
application.yml 放resources根目录下
路径优先级:
高优先级配置覆盖低,且会互补(并集合)
定时任务
定时任务有自己的线程池,不会和主线程冲突
spring提供的schedule 默认线程池是单一的