0
点赞
收藏
分享

微信扫一扫

【总结】自研Spring框架的实现总结

慎壹 2022-02-05 阅读 36

实例的创建

1、创建注解@Controller、@Service、@Repository、@Component

2、提取标记对象

实现思路

怎么根据包名获取类集合?

extractPacakgeClass里面需要完成的事情

Bean容器的实现与加载

导读:

因为需要同一个容器将所有需要管理的对象给管理起来,所以容器需要用单例来实现。

确保一个类只有一个实例,并对外提供统一访问方式。客户端不需要同时也无法实例化该类的对象。

实现:

构造容器我们使用线程安全的能抵御反射和序列化的枚举型的单例模式。

容器的组成部分

我们使用concurrentHashMap作为容器保存class对象和实例的载体。

并非所有class的对象都是容器管理的对象 ,而是从中选取配置里指定的class对象,也就是注解标记的对象,才将其存入载体并管理。

容器的加载:

实现思路

具体实现:

容器的操作方式

实现容器的操作方式
涉及到容器的增删改查

总结实现IoC容器:

依赖注入

了解Autowired的定义及使用:

@Target(ElementType.FIELD) //仅支持在成员变量上使用
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    String value() default "";
}
@Autowired(value = "HeadLineServiceImpl")//在使用的时候指定成员变量要注入的实现类
private HeadLineService headLineService;

IoC逻辑:

总结

AOP的实现

因为CGLIB动态代理不要求被代理类实现接口相对灵活,所以我们采用CGLIB的方式实现SpringAOP

思路:

◆解决标记的问题(识别Aspect以及Advice),定义横切逻辑的骨架

◆定义Aspect横切逻辑以及被代理方法的执行顺序

◆将横切逻辑织入到被代理的对象以生成动态代理对象

前提准备工作:

Pointcut解析器

直接给他赋值上Aspectj的所有表达式,以便支持对众多表达式的解析.

private PointcutParser pointcutParser=PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
      PointcutParser.getAllSupportedPointcutPrimitives()
);

表达式解析器

public PointcutLocator(String expression){
//在构造函数中利用AspectJ的切面表达式解析机制给成员变量赋值
  this.pointcutExpression=pointcutParser.parsePointcutExpression(expression);
}

定位

根据AspectJ的定位解析机制进行粗筛和细筛

5、定义一个类实现MethodInterceptor接口(作用是定义横切逻辑Aspect

这个类用于对每个被代理的对象进行方法拦截

intercept横切逻辑执行:

因为切面类集合本来就是按照order按照升序排序好的,上面的降序执行直接让集合从后向前遍历即可。

创建代理类

利用CGLIB的Enhancer创建代理类

public static Object createProxy(Class<?> targetClass, MethodInterceptor methodInterceptor){
    return  Enhancer.create(targetClass,methodInterceptor);
}

横切逻辑织入

doAOP

代码

public void doAop(){
    //1、获取所有的切面类
    Set<Class<?>> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
    if(ValidationUtil.isEmpty(aspectSet)){return;}//判空处理
    //2、拼接AspectInfoList
    List<AspectInfo> aspectInfoList=packAspectInfoList(aspectSet);
    //3、遍历容器里的类
    Set<Class<?>> classSet = beanContainer.getClasses();
    for (Class<?> targetClass : classSet) {
        //排除AspectClass自身
        if(targetClass.isAnnotationPresent(Aspect.class)){
            continue;
        }
        //4、粗筛符合条件的Aspect
        List<AspectInfo> roughMatchedAspectList=collectRoughMatchedAspectListForSpecificClass(aspectInfoList,targetClass);
        //5、尝试进行Aspect的织入
        wrapIfNecessary(roughMatchedAspectList,targetClass);
    }

MVC实现

image-20220205143934718

大致流程

获取http请求和需要回发的http响应对象,之后将他们委托给RequestProcessorChain处理。我们只处理get和post方法的请求,RequestProcessorChain参照的是责任链模式的后置处理器的处理逻辑,里面保存了处理RequestProcessor接口的多个不同的实现类,之所以会有多个不同的实现类对应为DispatcherServlet是项目里面所有请求的唯一入口。这些请求里即会有获取jsp页面的请求,也会有获取静态资源的请求、直接获取json数据的请求等,针对不同的请求会使用不同的RequestProcessor来处理。

DispatcherServlet实现

继承HttpServlet,重写init和service方法

init() 初始化

servlet是程序执行的入口:对容器进行初始化并将相关的bean加载进来,同时完成AOP相关逻辑的织入,以及相关的IoC依赖注入操作。同时为了后面能够采用责任链模式实现RequestProcessor矩阵,需要将对应的处理器添加到处理器列表中。

将请求处理器按照PreRequestProcessor、StaticResourceRequestProcessor、JspRequestProcessor、ControllerRequestProcessor进行添加。因为我们的请求经过编码和路径的处理之后再进行后续的处理。将ControllerRequestProcessor放到最后因为它的处理比较耗时,需要将请求和controller的方法实例进行匹配。

service方法实现

责任链模式(职责链模式)详解

ControllerRequestProcessor的实现

Controller请求处理器

功能:
前提准备:
实现:

1、依靠容器的能力,建立起请求路径、请求方法与Controller方法实例的映射

重写请求执行器RequestProcessor 里面的process方法

举报

相关推荐

0 条评论