框架和中间件

Spring Boot


AutoConfiguration 自动配置类,启动核心 


导入的类是注解实现的关键 


Spring
依赖对象的获得被反转了 例如,要获得一个Person对象,朴素的方法是取new 一个Person对象 而在控制反转,把创建对象的权利交给了别人,别人给你一个对象,直接拿来用就可以了(不是所有的对象都不用自己创建了,而是核心的,能够复用的对象由别人创建) 在编程中,有很多对象需要共用,之间有耦合、依赖关系,如果自己去维护,可能会出现问题,有可能业务发生变化的时候,会很麻烦;如果有了依赖注入,交给别人去管理,可以帮我们解决 



框架的开发者,用BeanFcatory,本质上是工厂,用来生产bean的 框架的使用者,用ApplicationContext 

装载bean,bean未必来源于磁盘上,jar包,也可能来源于内存,网络,数据库,动态代理创建bean bean的获取需要有人来完成,resourceLoader加载resource,从哪里加载resource接口有不同的实现,resourceLoader从不同的渠道把所要的bean信息加载到内存中,然后把信息读到以后,封装到beanDefinition里,于是就得到了抽象的bean

可以清晰的看到这里接口里面的方法,是判断资源的类型,是对资源访问的定义,可见,它代表的是一类资源 
ResourceLoader用来加载resource 用这两个接口就可以把资源加载到内存里 
BeanDefinition是对所有bean的一个抽象 
BeanDefinition抽象的实现AbstractBeanDefiniton 
构造器,初始化bean的过程 
初始化完以后,由BeanDefinitionRegistry注册到容器里,其实就是通过容器的方法,装到HashMap里 存放和删除的方法: 
刚刚是bean初始化和放到容器里面 但是bean之间还有依赖关系,依赖注入是重中之重 从左到右调用 
BeanFactory和FactoryBean有什么关系?在这里体现 缓存中没有,从当前工厂找,找不到,从父亲里找 mdb就是beanDefinition 
FactoryBean不是简单的bean,它能修饰别的bean,能产生别的bean 
例子: 首先一个普通的类AlphaObject,没有任何注解,启动的时候当然是不会放到spring容器里,
package com.nowcoder.seckill;
public class AlphaObject {
private String info;
public AlphaObject(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "AlphaObject{" +
"info='" + info + '\'' +
'}';
}
}
实现了FactoryBean接口,实际要产生的对象是AlphaObject这种类型的 现在有了这个注解,实现了这个接口,spring不会把AlphaObjectFactoryBean装到容器里,而是把接口所产生的对象装到容器里,装的是第一个方法返回的对象
所以FactoryBean的作用是装载一个特殊的对象,而不是这个对象本身
但是为什么不直接在那个类上加注解,放到容器里呢。这是因为有时候那个类可能不是自己写的,不能改,所以写这样一个类,由这个类来实现装到容器里;或者AOP底层是由动态代理实现的,如果动态代理现生成一个对象,可以用这种方式来处理 FactoryBean是为了装载比较复杂的,不好创建的目标bean
package com.nowcoder.seckill;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component("alphaObject")
public class AlphaObjectFactoryBean implements FactoryBean<AlphaObject> {
@Override
public AlphaObject getObject() throws Exception {
System.out.println("初始化AlphaObject...");
return new AlphaObject("alpha");
}
@Override
public Class<?> getObjectType() {
return AlphaObject.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public String toString() {
return "AlphaObjectFactoryBean{}";
}
}
测试类
package com.nowcoder.seckill;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@SpringBootTest
public class AlphaObjectFactoryBeanTest implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired
private AlphaObject alphaObject;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Test
public void test1() {
System.out.println(alphaObject);
System.out.println(applicationContext.getBean("alphaObject"));
System.out.println(applicationContext.getBean("&alphaObject"));
}
}
例如,要在很多方法开始的时候记录日志,我们可以把这个分散的关注点分离出来,封装一下,不在每一个地方分散的调用了 切面就是分散的关注点 

被代理的对象:就是分散的对象,有共同需求的分散的对象 连接点:被拦截对象的方法 切面:解决问题的类,在统一的类中编程,这个位置就叫做切面 
无接口的bean用CGLIB动态代理 

例子:
package example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo {
public static void main(String[] args) {
Vehicle v = new Car();
Vehicle p = (Vehicle) Proxy.newProxyInstance(
v.getClass().getClassLoader(), v.getClass().getInterfaces(), new VehicleProxy(v));
p.run(100);
}
}
interface Vehicle {
void run(int speed);
}
class Car implements Vehicle {
@Override
public void run(int speed) {
System.out.println("The car is running at " + speed + " km/h.");
}
}
class VehicleProxy implements InvocationHandler {
private Object target;
public VehicleProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(proxy.getClass().getName());
System.out.println(method.getName());
System.out.println(args == null ? null : args[0]);
System.out.println("before ... ");
Object obj = method.invoke(target, args);
System.out.println("after ...");
return obj;
}
}
输出: 

Spring MVC

Spring最终要执行的是Controller,执行的过程中会受到拦截器的拦截Interceptor 拦截器和Controller有什么关系,Controller由谁来调用,涉及到哪些组件呢
中间的DispathcherServlet是分发请求的,所有请求进来提交给DispathcherServlet,根据请求的路径url把请求分发给不同Controller的不同方法,是SpringMVC的核心
这个过程有4步: 第一步,遍历HandlerMapping,里面封装了URL和控制器的映射关系。SpringMVC也有自动配置类,自动配置类触发带有Controller注解的扫描,扫描到以后就会存到这里map里面。请求来了,就去找和当前路径匹配的HandlerMapping,里面不止有方法,还有拦截器 然后封装成一个chain,就知道先调谁后调谁
第二步:根据信息,实例化HandlerAdapter,也就是Controller,在控制器前后,可能有拦截器拦截,在这之前,调用拦截器的preHandler方法。调用完成以后,返回ModelAndView对象,里面封装了数据和模板路径
第三步:现在知道了视图在哪里,模板在哪里,数据是什么,然后调用ViewResolver,把信息给它,装到模板里去,然后调用view返回给客户端
第四步:在finally里面,调用afterComletion()方法 

|