1. 容器与Bean
1.1 容器接口
1.1.1 BeanFactory
- 到底么是 BeanFactory
它是 Applicationcontext 的父接口
它才是Spring的核心容器,主要的Applicationcontext实现都组合了它的功能
- BeanFactory 能干点啥
表面上只有getBean
实际上控制反转、基本的依赖注入、直至 Bean的生命周期的各种功能,都由它的实现类提供
1.1.2 ApplicationContext
- Applicationcontext 比 BeanFactory多点啥
//设置多语言显示
ConfigurableApplicationContext context = SpringApplication.run(ManagerServerApplication.class, args);
system. out.println(context.getNessage( code: "hi",args: null,Locale.CHINA));
system.out.println(context.getNessage( code: "hi",args: null,Locale.ENGLISH));
system.out.println(context.getNessage( code:"hi",args: null,Locale.JAPANESE));
//加载资源
Resource[] resources = context.getResources( “classpath*:HETA-INF/spring .factories")
for (Resource resource : resources) {
system.out.println(resource);
}
//获取配置文件的值
system.out.println(context.getEnvironment().getProperty("java_home"));
system.out.println(context.getEnvironment().getProperty( "server.port"));
//发布事件
//参数为自定义的用户注册事件
@Autowired
private ApplicationEventPublisher context;
public void register() {
log.debug("用户注册");
context.publishEvent(new UserRegisteredEvent(this));
)
//在需要接收事件的方法上添加 @EventListener 注解
@EventListener
public void aaa(UserRegisteredEvent event) {
log.debug("{(J", event);
//注册发邮件发短信等行为
}
1.2 容器实现
1.2.1 BeanFactory实现的特点
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//bean的定义 calss scope 初始化 销毁
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(自定义beanName.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition(自定义的beanName,beanDefinition);
//给beanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//给beanFactory 后处理器的主要功能 , 补充一些bean定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
//bean后处理器,针对bean的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
beanFactory不会做的事
- 不会主动调用BeanFactory后处理器
- 不会主动添加 Bean后处理器
- 不会主动初始化单例
- 不会解析 beanFactory 还不会解析 ${} 与 #{}
1.2.2 ApplicationContext的常见实现和用法
// 1. 较为经典的容嚣,基于 classpath下 xml格式的配置文件来创建
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( " classpath下 xml文件名" );
// 2. 基于磁盘路经下xml格式的配置文件来创建
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext( " 磁盘路径下 xml文件名 " );
//3. 较为经典的容器 ,基于java 配置类来创建
AnnotationConfigApplicationContext context2 = new AnnotationConfigApplicationContext( " 自定义配置类.class" );
// 4. 较为经典的容器, 基于java配置类来创建. 用于web环境
AnnotationConfigServletWebServerApplicationContext context3 = new AnnotationConfigServletWebServerApplicationContext( " 自定义配置类.class" );
//如果使用第四种,那么自定义的配置类需要包含如下三个bean
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet(){
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(){
return new DispatcherServletRegistrationBean(dispatcherServlet() , "/");
}
//打印beanname
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
1.3 Bean的生命周期
构造 --> 依赖注入 --> 初始化 --> 销毁
- Bean的后置处理器会在 不同阶段进行增强实现
实例化之前增强
构造
实例化之后增强
依赖注入之前增强
依赖注入
初始化之前增强
初始化
初始化之后增强
销毁之前增强
销毁
1.4 Bean后处理器
Bean后处理器的作用: 为 Bean生命周期各个阶段提供扩展
1.4.1 常见的后处理器
- AutowiredAnnotationBeanPostProcessor
会在依赖注入阶段解析处理 @Autowired @value 进行注入
- CommonAnnotationBeanPostProcessor
在依赖注入阶段会解析执行 @Resource
在初始化前会解析处理 @PostConstruct
在销毁前解析处理 @PreDestroy
- ConfigunationPropertiesBindingPostProcessor
会在初始化之前解析处理@ConfigurationProperties
1.4 BeanFactory后处理器
BeanFactory后处理器的作用: 为 BeanFactory提供扩展
1.5 Spring Bean 的初始化与销毁
初始化方法:,以及执行排序
- @postconstruct注解
- 实现 initializingBean接口,并实现afterpropertiesset()方法
- @bean(initMethod = “自定义初始化方法”)
销毁方法,以及执行排序
- @predestroy
- 实现disposableBean接口并实现destroy()方法
- @Bean(destroyMethod = “自定义销毁方法”)
1.8 Scope
- scope类型
- singleton : 每次从容器中获取bean的时候,取出来都是同一个对象
- prototype : 每次从容器中获取bean的时候,每次都会产生新的对象
- request : bean跟request请求域绑定,每次进来一个请求新建一个对象与之绑定,请求结束bean销毁
- session : bean跟会话绑定,会话开始对象创建,会话结束对象销毁
- application : bean跟应用程序域绑定,应用启动对象创建,应用程序结束对象销毁
2. AOP
2.1 aop实现方式之 ajc 增强
利用插件aspectj直接修改class文件来实现增强
2.2 aop实现方式之 agent 增强
在导入aspectjweaver依赖之后,同时在VM options中加入
-javaagent:本地maven仓库\aspectjweaver-1.9.7.jar
2.3 aop实现方式之 proxy 增强
2.3.1 jdk动态代理
只能针对接口代理
代理类和目标类是同级关系,实现了共同的接口,使用反射实现方法增强
代理对象执行的方法都会通过InvocationHandler中的invoke方法来执行
jdk做了优化,在执行第17次的时候,不用反射调用而是做了方法的直接调用,
2.3.2 cglib动态代理
代理是子类型,目标是父类型,是对原有方法进行了重写以达到增强目的
spring默认使用methodproxy.invoke(target,args) , 内部没有用反射,是直接调用,需要目标类target
代理对象执行的方法都会通过methodInterceptor.intercept()方法,方法内部执行methodProxy.invole()方法
method.invoke(target,args); //反射调用
methodProxy.invole(target,args); //内部无反射,结合目标类target,spring默认
methodProxy.invokeSuper(p,args); //内部无反射,结合代理对象用, p:代理对象
- cglib 无反射调用,是如何实现的呢?
- methodProxy.create()
创建methodProxy时,底层会创建FastClass代理类,可以避免方法的反射调用.
如何避免反射呢? 是在创建methodProxy时会生成方法签名signature(包含方法名,以及参数类型和返回值类型),针对于方法签名根据FastClass代理类的getindex()方法获取目标方法的的下标index
- methodProxy.invole(target,args)
在执行invoke()方法时,会传入目标类target和参数,在invoke内部会执行FastClass代理类的invoke()方法,在FastClass代理类的invoke()方法内部已经知道了目标方法的索引以及目标类target以及参数args,完成方法的直接调用即可
2.3.3 jdk动态代理与cglib代理对比
cglib(code generator library 代码生成库)代理的是字节码对象(即Class),而JDK动态代理代理的是对象
jdk是一共十七次调用,前十六次是通过反射调用,最后一次是针对一个方法产生一个代理类
,这个代理类把本来的反射调用修改为无需反射,直接调用目标方法
cglib直接就创建代理类对象,一个代理类会创建两个FastClass类对象(TargetFastClass配合目标类对象调用、ProxyFastClass配合代理类对象调用)
2.3.4 spring如何选择代理对象
ProxyFactory
是用来创建代理的核心实现, 用AopProxyFactory选择具体代理实现
proxyTargetClass
: proxyFactory里边的配置类proxyConfig的一个属性
也可以通过主启动类注解配置@EnableAspectJAutoProxy(ProxyTargetClass = false/true)
如果proxyTargetClass = false ,目标实现了接口,用jdk实现
如果proxyTargetClass = false ,目标没有实现接口,用cglib实现
如果proxyTargetClass = true ,总是使用cglib实现
2.3.5 代理对象的创建时机
创建 --> (*) 依赖注入 --> 初始化(*)
-
代理的创建时机
- 无循环依赖 : 初始化之后
- 有循环依赖 : 实例创建后,依赖注入前,并暂存于二级缓存
-
依赖注入与初始化不应该被增强,仍应该施加于原始对象
3. Web MVC
3.1 SpringMVC DispatchServlet初始化九大加载策略
DispatcherServlet初始化的时候会执行onRefresh(Application context)方法,从而调用initStrategies(Application context)方法,在该方法内部会初始化九大方法,
- initMultipartResolver(context) : 文件上传
相应的请求会被DispatchServlet的doDispatch方法拦截,doDispatch方法中共首先就会调用checkMultipart()
方法检查请求是否是包含文件流
- initLocalReslover(context) : java国际化
DispatchServlet中定义一个静态的容器初始化默认defaultStrategies
方法块,如果用户没有自定义的话,就使用默认的.
SpringMVC国际化提供了四个国际化的实现的类AcceptHeaderLocaleResolver(默认), FixedLocaleResolver、 CookieLocaleResolver SessionLocaleResolver
。
- initThemeResolver(context) : 主题
要在程序中使用主题,必须设置一个org.springframework.ui.context.ThemeSource的实现类
SpringMVC中有实现主题类有3个:
- FixedThemeResolver(默认):固定格式的theme,不能在系统运行时动态更改theme。
- SessionThemeResolver:可在运行中通过更改cookie中的相应的key值来动态调整theme的值。
- CookieThemeResolver:可在运行中通过更改session中的相应的key值来动态调整theme的值
主题加载策略和initLocaleResolver类似,也是如果用户没有自定义就采用默认的方式。默认的方式为FixedThemeResolver。
- initHandlerMapings(context) : 请求分发,路径匹配
RequestMappingHandlerMapping 和 BeanNameUrlHandlerMapping
RequestMappingHandlerMapping
用于注解@Controller,@RequestMapping来定义controller,主要作用是将Controller的注解值(类路径及方法路径)与Controller实例映射起来
BeanNameUrlHandlerMapping
通过配置文件,把一个URL映射到Controller
- initHandlerAdapters(context) : 请求handler处理器
HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。
当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理
- initHandlerExceptionResolvers(context) : 请求异常
由对象实现的接口,可以解析在处理程序映射或执行期间抛出的异常,尤其是在视图解析是发生的异常错误。 HandlerExceptionResolver实现者通常在应用程序上下文中注册为bean。 错误视图类似于JSP错误页面,但可以与任何类型的异常一起使用,包括任何已检查的异常,以及特定处理程序的潜在细粒度映射。
- initRequestToviewNameTranslator(context) : 请求视图名
RequestToViewNameTranslator主要是获取请求中的viewName,然后可以根据这个viewName获取ModelAndView对象,简单的来说就是根据request请求获取来组装视图名称
- initviewResolvers(context) : 视图解析器
ViewResolvers是一个List类型数据,视图解析是链式的,如果一个视图解析器根据viewName和local
参数没有找到对应的View,则开始使用第二的解析器来进行查询,直到找到为止。默认的ViewResolvers为InternalResourceViewResolver
- initFlashMapManager(context) : 重定向属性存储
FlashMapManager用于检索和保存FlashMap实例的策略界面
FlashMap简单来说就是一个HashMap,用于数据保存,主要作用于重定向,springMVC中默认的FlashMapManager为SessionFlashMapManager