第一章、spring 知识点梳理
文档我已经上传, 地址 : https://download.csdn.net/download/m0_37156901/11994761
-----------------------------------------------------------------------------------------------------------------------------------
- 课程目标
- Spring基础知识点梳理(IoC、DI、AOP、BeanFactory、ApplicationContext)
- 如何理解web工程创建spring容器的过程
- 剖析spring IoC容器的初始化过程(重点)
- 实战应用之spring容器错误解决
- spring知识点梳理
- spring的官方网址:spring.io
- 我们经常说的Spring其实指的是Spring Framework(spring 框架)。
- Spring框架的核心就是IoC(控制反转)和AOP(面向切面编程)。
*** IoC简单理解就是控制对象创建的角色由程序员反转为Spring IoC容器。
*** AOP简单理解就是针对目标对象进行动态代理,横向增强JavaBean的功能。
- Spring IoC容器本质上就是创建类的实例的工厂,并且对类的实例进行管理。
- Spring IoC容器需要通过Bean工厂来实现,在Spring框架中,主要有两个工厂接口:BeanFactory接口和ApplicationContext接口(实现了BeanFactory接口)。
***其中BeanFactory接口是Spring早期创建Bean对象的工厂接口。
***而我们现在大多数是通过ApplicationContext接口进行Bean工厂的创建。
- Spring IoC 容器加载Bean信息的方式有XML配置方式和注解方式。
***XML配置方式:bean标签
***注解方式:@Component、@Controller、@Service、@Repository,需要使用context:component-scan标签配合使用。
- Spring IoC容器的创建方式主要有两种场景:在Java Application中创建(jar包)和在Web Application(war包)中创建(重点)。
***在Java Application中创建Spring IoC容器主要是通过ApplicationContext接口的两个实现类来完成的:ClassPathXmlApplicationContext 和FileSystemXmlApplicationContext 。
***在Web Application中创建Spring IoC容器主要是通过ApplicationContext接口的子接口WebApplicationContext来实现的。
***WebApplicationContext是通过ContextLoaderListener(实现ServletContextListener接口)创建之后,放入ServletContext域对象中的。
- Spring DI(依赖注入)是基于IoC使用的。简单理解就是Bean工厂在生成Bean对象的时候,如果Bean对象需要装配一个属性,那么就会通过DI将属性值注入给对象的属性。
***依赖注入的方式主要有构造方法注入(了解)和set方法注入(重点)。
***set方法注入又分为手动装配方式注入和自动装配方式注入。
***手动装配方式(XML方式):bean标签的子标签property,需要在类中指定set方法。
***自动装配方式(注解方式):@Autowired注解、@Resource注解。
***@Autowired:一部分功能是查找实例,从spring容器中根据类型(java类)获取对应的实例。另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值。(注意事项:一个java类型在同一个spring容器中,只能有一个实例)
***@Resource:一部分功能是查找实例,从spring容器中根据Bean的名称(bean标签的名称)获取对应的实例。另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值。
- Spring AOP实现原理是什么?
***动态代理技术(反射):基于JDK的动态代理和使用CGLib的动态代理。
***动态代理方式选择:根据是否实现接口来选择哪种代理方式。
- Spring 基于AspectJ的AOP开发
- spring容器初始化过程
什么是web服务器(Servlet容器)? Tomcat、Jetty、Jboss等
什么是web容器? ServletContext(Servlet上下文)、Servlet三大域对象(生命周期范围最大的一个)
什么是spring容器?ApplicationContext(Spring上下文,实现了BeanFactory)
-
- web容器初始化过程
- web服务器(tomcat)启动会加载web.xml(启动ContextLoaderListener监听器):
- web服务器启动后,会创建ServletContext(web上下文,也就是web容器),此时会触发ContextLoaderListener监听器的contextInitialized()方法。
- contextInitialized()方法中会调用initWebApplicationContext()方法,该方法负责创建Spring容器和生产Bean对象。
- initWebApplicationContext()方法负责创建WebApplicationContext,通过createWebApplicationContext()方法
***WebApplicationContext是一个接口,此处创建的是它的默认实现类:XmlWebApplicationContext(web环境中的真正容器)
- 加载spring配置文件,并创建beans。通过configureAndRefreshWebApplicationContext()方法
- 将spring容器context挂载到ServletContext 这个web容器上下文中。通过servletContext.setAttribute()方法。
【Web三类八种监听器】: ***监听域对象的生命周期: *ServletContextListener: *创建:服务器启动 *销毁:服务器正常关闭 *spring ContextLoaderListener(服务器启动时负责加载Spring配置文件) *HttpSessionListener *创建:第一次访问request.getHttpSession(); *销毁:调用invalidate();非法关闭;过期 *ServletRequestListener *创建:每一次访问 *销毁:响应结束 ***监听域对象的属性:(添加、删除、替换) * ServletContextAttributeListener * HttpSessionAttributeListener * ServletRequestAttributeListener ***监听HttpSession中JavaBean的改变: * HttpSessionBindingListener(HttpSession和JavaBean对象的绑定和解绑) * HttpSessionActivationListener(HttpSession的序列化,活化、钝化)
|
-
- spring容器初始化过程
流程说明:
1、ResourceLoader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件的资源;
2、BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
3、容器扫描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射机制自动识别出Bean工厂后处理后器(实现BeanFactoryPostProcessor接口)的Bean,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理。主要完成以下两项工作:
1)对使用到占位符的<bean>元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BeanDefinition对象进行加工处理并得到成品的BeanDefinition对象;
2)对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor接口的Bean),并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry);
4.Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStrategy着手进行Bean实例化的工作;
5.在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作;
6.利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。
Spring容器确实堪称一部设计精密的机器,其内部拥有众多的组件和装置。Spring的高明之处在于,它使用众多接口描绘出了所有装置的蓝图,构建好Spring的骨架,继而通过继承体系层层推演,不断丰富,最终让Spring成为有血有肉的完整的框架。所以查看Spring框架的源码时,有两条清晰可见的脉络:
1)接口层描述了容器的重要组件及组件间的协作关系;
2)继承体系逐步实现组件的各项功能。
接口层清晰地勾勒出Spring框架的高层功能,框架脉络呼之欲出。有了接口层抽象的描述后,不但Spring自己可以提供具体的实现,任何第三方组织也可以提供不同实现, 可以说Spring完善的接口层使框架的扩展性得到了很好的保证。纵向继承体系的逐步扩展,分步骤地实现框架的功能,这种实现方案保证了框架功能不会堆积在某些类的身上,造成过重的代码逻辑负载,框架的复杂度被完美地分解开了。
Spring组件按其所承担的角色可以划分为两类:
1)物料组件:Resource、BeanDefinition、PropertyEditor以及最终的Bean等,它们是加工流程中被加工、被消费的组件,就像流水线上被加工的物料;
2)加工设备组件:ResourceLoader、BeanDefinitionReader、BeanFactoryPostProcessor、InstantiationStrategy以及BeanWrapper等组件像是流水线上不同环节的加工设备,对物料组件进行加工处理。
摘录于《Spring 3.x 企业应用实战》
- 案例分析context:property-placeholder
默认就是使用PropertyPlaceholderConfigurer类实现。
<context:property-placeholder location="classpath:db.properties" />作用的解读
第二章、spring 核心技术知识点
-----------------------------------------------------------------------------------------------------------------------------------
参见我的上传文档08spring讲义
第三章、spring aop 面向切面代理的实现
详细内容参见文档 ,我已经上传了文档, 可以去下载 https://download.csdn.net/download/m0_37156901/12009158
3.1 jdk 和 cglib 的 实现
/*** 代理 - 增强效果* 使用JDK的动态代理实现 它是基于接口实现的*/
public class mProxyUtils {
/** 1. jdk 反射实现 static 关键字不用new class 直接调用*/
public static UserService getProxy(final UserServiceImpl userService){
UserService proxyInstance = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
/**
* Proxy是JDK中的API类
* 第一个参数:目标对象的类加载器
* 第二个参数:目标对象的接口
* 第二个参数:代理对象的执行处理器
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在这里前后进行增强
System.out.println("jdk proxy init...");
// 下面的代码,是反射中的API用法
// 该行代码,实际调用的是目标对象的方法
Object obj = method.invoke(userService, args);
System.out.println("jdk proxy finally ...");
return obj;
}
});
return proxyInstance;
}
/**使用CGLib动态代理技术实现 它是基于继承的方式实现的*/
public static UserService getProxyByCGlib(UserServiceImpl userService){
// 1 创建增强器
Enhancer enhancer = new Enhancer();
// 2 设置目标类为父类
enhancer.setSuperclass(userService.getClass());
// 3 设置回调函数
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cg lib start ....");
// 因为代理对象是目标对象的子类
// 该行代码,实际调用的是目标对象的方法
// object :代理对象
Object invokeSuper = methodProxy.invokeSuper(obj, args);
System.out.println("cg lib ended ....");
return invokeSuper;
}
});
// 4 获取增强之后的代理对象
UserService cgProxy = (UserService) enhancer.create();
return cgProxy;
}
}
3.2. aop xml 自定义实现
//@Aspect:标记该类是一个切面类
@Aspect
// 需要将切面类交给Spring IoC容器管理
@Component("myAspect")
public class MyAspect {
//切入点表达式
private static final String str="execution(* *..*.*ServiceImpl.*(..))";
// @Before:定义该方法是一个前置通知
/*@Before(value = "execution(* *..*.*ServiceImpl.*(..))")
public void before() {
System.out.println("注解前置通知");
}
@Before(value = "fn()")
public void before() {
System.out.println("注解前置通知");
}
//使用PointCut注解,来定义一个通用切入点表达式
@Pointcut(value=str)
public void fn() {}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 组件扫描器,扫描切面类 -->
<context:component-scan base-package="com.kkb.spring"></context:component-scan>
<!-- 开启AOP自动代理 -->
<aop:aspectj-autoproxy/>
</beans>