Spring的优势:
1. 解耦合, 简化开发
2. AOP编程的支持
3. 声明式事务的支持
4. 方便程序的测试
5. 方便集成各种优秀框架
Spring的核心结构:
web模块, 数据访问与集成,Test模块,
AOP模块, Core Container模块
核心思想:
错误认知:IOC容器(是一个map而已; 准确来说, map是ioc容器的一个成员,叫做单例池
singletonObjects, 容器是一组组件和过程的集合, 包括BeanFactory, 单例池, BeanPostProcessor等之间的协助流程)
什么是IOC?Inversion of Control 是技术思想
问题:创建A对象, 而A对象依赖与B对象, 这时候如果B对象的实例类发生了改变, 那么A对象的代码也需要改变, 显然, A和B耦合在一起!
Control : 指对象的创建(实例化, 管理) 的权利
Inversion : 把控制权交由Spring.
IOC与DI的区别? Dependancy Injection 依赖注入
什么是AOP?
静态代理: 需要为每个业务创建一个代理类。
动态代理:
JDK
public interface RentingHouse{
public void rentHouse ;
}
public class RentingHouseImpl implements RentingHouse {
public void rentHouse() {
System.out.pringln("我要租房子") ;
}
}
public class JdkProxy {
public static void main(String args[]) {
// 委托对象
RentingHouse rentHouse = new RentingHouseImpl () ;
// 获取代理对象
Object proxy = Proxy.newProxyInstance(
rentHouse.getClass().getClassLoader,
rentHouse.getClass().getInterfaces(),
new InvocationHanler() {
public Object invoke(Object proxy, Method method, Object[] args) {
System.out.pringln("代理前") ;
Object result = method.invoke(proxy, args)
System.out.pringln("代理后") ;
return result ;
}
});
}
}
CGLIB:
// cglib代理需要添加依赖
public class CglibProxy {
public static void main(String args[]) {
// 委托对象
RentingHouse rentHouse = new RentingHouseImpl () ;
// 获取代理对象
Object proxy = Enhancer.create(
rentHouse.getClass(),
// 需要一个拦截器
new MethodInterceptor() {
public Object invoke(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) {
System.out.pringln("代理前") ;
Object result = method.invoke(proxy, args)
System.out.pringln("代理后") ;
return result ;
}
});
}
区别: JDK委托对象必须实现接口, CGLIB没有这个规定!
SpringBean的生命周期:
1. 实例化bean:
根据配置情况调用,Bean构造方法或工厂方法实例化对象
2. 设置属性值
利用依赖注入完成bean的所有属性值得配置注入
3. 调用BeanNameAware的setBeanName()
如果实现了这个接口, 则调用setBeanName
4. 调用 BeanFactoryAware的setBeanFactory() ;
如果实现了这个接口, 则调用setBeanFactory
5. 调用ApplicationAware的setApplicaitonContext()
如果实现了这个接口, 则调用setApplicaitonContext, 当前得ApplicaitonContext实例引用
6. 调用BeanPostProcessor()
如果BeanPostProcessor与Bean关联, 则Spring将调用该接口得预初始方法, postProcessBeforeInitialzation() 对Bean进行加工, Spring得AOP就是利用它实现得
7. 调用InitializingBean的afterPropertiesSet()
9. 调用BeanPostProcessor()后初始化方法
11. 如果 Bean 实现了 DisposableBean 接⼝,则 Spring 会调⽤ destory() ⽅法将 Spring 中的 Bean 销毁; 如果在配置⽂件中通过 destory-method 属性指定了 Bean 的销毁⽅法,则 Spring 将调⽤该⽅法对 Bean 进⾏销毁。
BeanDefifinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个 JavaBean, 这个JavaBean 就是 BeanDefifinition
BeanFactory和 FactoryBean :
FactoryBean案列:
@Data
public class Company {
private String name;
private String address;
private int scale;
@Override
public String toString() {
return "Company{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", scale=" + scale +
'}';
}
}
public class CompanyFactoryBean implements FactoryBean<Company> {
private String companyInfo ; // 公司名称,地址,规模
public void setCompanyInfo(String companyInfo) {
this.companyInfo = companyInfo ;
}
@Override
@Bean
public Company getObject() throws Exception {
// 模拟创建复杂对象Company
Company company = new Company();
String[] split = companyInfo.split(",");
company.setName(split[0]);
company.setAddress(split[1]);
company.setScale(Integer.parseInt(split[2]));
return company;
}
@Override
public Class<?> getObjectType() {
return Company.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Object bean = context.getBean("companyBean");
System.out.println("bean: " + bean);
Object bean1 = context.getBean("&companyBean");
System.out.println(bean1);
}
<!-- <bean id="companyBean" class="com.leiyu.factory.CompanyFactoryBean">-->
<!-- <property name="companyInfo" value="拉勾,中关村,500"/>-->
<!-- </bean>-->
后置处理器:
Spring提供了两种后置处理器:分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。
工厂初始化:BeanFactory ---> Bean对象
在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置一些事情, 比如我们可以获取到BeanDefifinition对象, 以⼿动修改bean标签中所定义的属性值。
public class FactoryBeanDemo implements BeanFactoryPostProcessor {
/**
* BeanFactory级别的处理,是针对整个Bean的⼯⼚进⾏处理
* 典型应⽤:PropertyPlaceholderConfigurer
* @param configurableListableBeanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("xxx");
beanDefinition.setBeanClassName("xxx");
}
}
/**
* 该接⼝提供了两个⽅法,分别在Bean的初始化⽅法前和初始化⽅法后执⾏,
*/
public class SpringBeanDemo implements BeanPostProcessor {
/**
* 默认对所有Bean进行处理
* @param bean 每个bean的实例
* @param beanName 每个bean的name 或 id 值, 我们可以通过这个参数来判断具体的bean
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
注意:对象不⼀定是SpringBean,⽽SpringBean⼀定是个对象
IOC容器初始化读取流程:
1. 根据SpringBean生命周期得时机点:根据栈得信息
构造器,初始化执行方法都经过, bean后置处理器得before()/after(): AbstractApplicationContext#refresh#finishBeanFactoryInitialization
Bean工厂后置处理器初始化,方法执行:
AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
BeanPostProcessor后置处理器初始化:
AbstractApplicationContext#refresh#RegisterBeanPostProcessors
2. 代码时机锁定到了refresh() IOC容器创建得核心方法, spring提供给我们,一个容器启动后,还可以刷新这个容器。
a.进去后首先有一个Synchtonized对象锁和close()互斥, 保证在刷新得时候不能close()
b.
// 刷新前的预处理:设置启动时机, 开启活跃状态, 验证环境信息里一些必要的属性
protected void prepareRefresh() {
// 启动日期和活动标志
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (this.logger.isDebugEnabled()) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Refreshing " + this);
} else {
this.logger.debug("Refreshing " + this.getDisplayName());
}
}
// 设计模式中模板方法模式--也叫做钩子方法
this.initPropertySources(); // 可拓展, 给子类自定义容器, 可以在这个方法内说明
this.getEnvironment().validateRequiredProperties(); // 验证环境信息里一些必要的属性
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
} else {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
this.earlyApplicationEvents = new LinkedHashSet();
}
c. 创建工厂, 把xml中Bean对象封装成BeanDefinition
// 比较关键的一步
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
d. Beanfactory的预准备工作(比如context的类加载信息)
this.prepareBeanFactory(beanFactory);
e. 刚才是前置, 现在是BeanFactory预准备工作完成后, 进行后置处理工作
this.postProcessBeanFactory(beanFactory);
// 这里也是没有进行实现的, 模板方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
f. 实例化实现了BeanFactoryPostProcessor接口的Bean, 要开始调用接口方法了
this.invokeBeanFactoryPostProcessors(beanFactory);
g.到这里, bean还没有被实例化, 指注册Bean的后置处理器, 在创建Bean前后执行
this.registerBeanPostProcessors(beanFactory);
h. 初始化Message组件(做国际化功能, 消息绑定, 解析)
i. 初始化事件派发器
j. onRefresh()也是让子类从写, 在容器刷新时可以自定义逻辑, 如创建Tomcat
k.registerListeners() 注册应用监听器, 就是实现了ApplicatioListeners的bean要注册进来
l. 初始化剩下的非懒加载单例bean, 创建实例bean, 填充属性, 初始化方法的调用(
afterPropertiesSet(), init-method() ) 调用BeanPostProcessor对实例Bean进行后置处理
this.finishBeanFactoryInitialization(beanFactory);
m. this.finishRefresh();
BeanFactory创建的子流程:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
return this.getBeanFactory();
}
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经有了 BeanFactory
if (this.hasBeanFactory()) { // 内部加了同步关键字
// 销毁
this.destroyBeans();
// 关闭
this.closeBeanFactory();
}
try {
// 实例化 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
// 设置序列化ID
beanFactory.setSerializationId(this.getId());
//自定义bean工厂的一些属性(id相同是否覆盖,是否循序循环依赖)
this.customizeBeanFactory(beanFactory);
// 加载应用中的Definition
this.loadBeanDefinitions(beanFactory);
// 赋值给当前的factory
this.beanFactory = beanFactory;
} catch (IOException var2) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
}
}
BeanDefinition 的注册
// 从创建工厂中进入 // 加载应用中的Definition this.loadBeanDefinitions(beanFactory);
// 来到org.springframework.context.support.AbstractRefreshableConfigApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 给指定的BeanFactory创建一个XmlBeanDefinitionReader读取器, 解析xml对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 给XmlBeanDefinitionReader设置context上下文中的环境属性
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 提供子类实现提供的一些自定义初始化策略 构子方法
this.initBeanDefinitionReader(beanDefinitionReader);
// 真正去加载beanDefinitions
this.loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 从Resource 资源对象加载beanDefinitions
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
// 如果有多个配置文件循环读取
//org.springframework.beans.factory.support.AbstractBeanDefinitionReader
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
String[] var3 = locations;
int var4 = locations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
count += this.loadBeanDefinitions(location);
}
return count;
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 获取上下文的资源加载器
ResourceLoader resourceLoader = this.getResourceLoader();
// 判断资源加载器是否为ResourcePatternResolver xml url等不同类型统一接口
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
} else {
int count;
if (resourceLoader instanceof ResourcePatternResolver) {
try {
// 统一加载转换为Resource资源对象
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
// 加载资源中配置的BeanDefinition对象, 返回数量
count = this.loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
return count;
}
}
}
// 刚才的for是循环xml文件, 这个for 是循环抽象后的Resource资源文件
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
Resource[] var3 = resources;
int var4 = resources.length;
for(int var5 = 0; var5 < var4; ++var5) {
Resource resource = var3[var5];
count += this.loadBeanDefinitions((Resource)resource);
}
return count;
}
Bean创建流程
// 1. this.finishBeanFactoryInitialization(beanFactory);
// 2. public void preInstantiateSingletons() throws BeansException
// 3. protected <T> T doGetBean
Spring IOC 循环依赖 : 解决循环依赖靠的是三级缓存
一级:单例池 二级: early 三级: singletonFactorys
理论说明:BeanA 和 BeanB 循环依赖
1. 当A实例化后里面暴漏在三级缓存, 当时B也不列外
2. 这时候B创建时发现依赖于A, 即使用尚未成型的A。
3. 升级放入二级缓存, (这个时候可以做很多事情)
4. B这个时候已经创建完成放入一级缓存
5. A这个时候就可以使用一级缓存的成型的B
Spring AOP 应用
<bean id="logUtil" class="com.leiyu.main.LogUtil"></bean>
<!--开始aop的配置-->
<aop:config>
<!--配置切面-->
<aop:aspect id="logAspect" ref="logUtil">
<aop:pointcut id="pt1" expression="execution(* com.leiyu.factory.CompanyFactoryBean.getObject(*))"/>
<!--配置前置通知-->
<aop:before method="beforeMethod" pointcut-ref="pt1"></aop:before>
</aop:aspect>
</aop:config>
注解模式:
@Component
@Aspect
class LogUtil {
@Pointcut("execution(* com.lagou.service.impl.*.*(..))")
public void pointcut(){}
@Before("pointcut()")
public void beforePrintLog(JoinPoint jp){
Object[] args = jp.getArgs();
System.out.println("前置通知:beforePrintLog,参数是:"+
Arrays.toString(args));
}
}
<!--开启spring对注解aop的⽀持-->
<aop:aspectj-autoproxy/>