手写简易Spring,Spring mvc。

@author 吴星辰

以下版本都是简易版,后期将会更新更完整的版本

版本一:面对过程化,简易实现Spring ioc DI与Spring MVC

由于面试过程版,简单,不多说,贴部分代码,明眼人一看就懂
先带上目录结构:
在这里插入图片描述
首先我们知道,web.xml是mvc项目的启动点。我们配置自己的Servlet。
在这里插入图片描述
回到我们自己定义的Servlet中进行业务:
init关键的步骤:

 //1、加载配置文件
        doLoadConfig(config.getInitParameter("contextConfigLocation"));
        //2、扫描相关的类
        doScanner(contextConfig.getProperty("scanPackage"));
        //3、初始化扫描到的类,并且放入到IOC容器之中
        doInstance();
        //=========  DI =========
        //4、完成自动化的依赖注入
        doAutowired();
        //======= MVC =============
        //5、初始化HandlerMapping
        doInitHandlerMapping();

定义常规容器:

//保存application.properties配置文件中的内容
    private Properties contextConfig = new Properties();
    //保存扫描的所有的类名
    private List<String> classNames = new ArrayList<String>();
    //为了简化程序,暂时不考虑ConcurrentHashMap
    // 主要还是关注设计思想和原理
    private Map<String,Object> ioc = new HashMap<String,Object>();
    //保存url和Method的对应关系
    private Map<String,Method> handlerMapping = new HashMap<String,Method>();

准备就绪:


```java
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    //6、根据url调用method
    try {
        doDispatch(req,resp);
    } catch (Exception e) {
        e.printStackTrace();
        resp.getWriter().write("500 Exception,Detail: " + Arrays.toString(e.getStackTrace()));
    }

}

private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    String url = req.getRequestURI();
    String contextPath = req.getContextPath();
    url = url.replaceAll(contextPath,"").replaceAll("/+","/");

    if(!this.handlerMapping.containsKey(url)){
        resp.getWriter().write("404 Not Found!!");
        return;
    }

    Method method = this.handlerMapping.get(url);

    Map<String,String[]> paramsMap = req.getParameterMap();

    //实参列表
    //实参列表要根据形参列表才能决定,首先得拿到形参列表
    Class<?> [] paramterTypes = method.getParameterTypes();

    Object [] parameValues = new Object[paramterTypes.length];
    for (int i = 0; i <paramterTypes.length; i ++){
        Class paramterType = paramterTypes[i];
        if(paramterType == HttpServletRequest.class){
            parameValues[i] = req;
            continue;
        }else if(paramterType == HttpServletResponse.class){
            parameValues[i] = resp;
            continue;
        }else if(paramterType == String.class){
            Annotation[][] pa = method.getParameterAnnotations();
            System.out.println("debug.....");
            for (int j = 0; j < pa.length; j ++){
                for (Annotation a : pa[i]) {
                    if(a instanceof RequestParam){
                        String paramName = ((RequestParam) a).value();
                        if(!"".equals(paramName.trim())){
                            String value = Arrays.toString(paramsMap.get(paramName))
                                    .replaceAll("\\[|\\]","")      //正则处理[]
                                    .replaceAll("\\s",",");   //正则处理空格
                            parameValues[i] = value;
                        }
                    }
                }
            }
        }
    }

    String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
    method.invoke(ioc.get(beanName),parameValues);
}

`

第二版;面对对象版 实现spring ioc ,aop,DI mvc

我们先来完成 ioc 与DI .

我们先来定义几个类:

核心类:ApplicationContext
存放配置文件类: BeanDefintion
加载处理配置文件的的类: BeanDefintionReader
保存实例:BeanWrapper

 public class BeanDefinition {
    //key值
    private String factoryBeanName;
    //全限定名
    private String beanClassName;   } 
public class BeanWrapper {
    private Object wrapperInstance;
    private Class<?> wrappedClass;

}

init当中的除了handle,别的都需要到application里来处理:

application的容器:

先聊一聊步骤然后直接贴代码
第一步加载配置文件扫描对应的包 生成BeanDeFinition的map。

第二,这里我使用的是加ioc容器和注入同时进入,详见getBean;逻辑,这样能在初始化阶段没有注入完成,但是不碍事,因为后面我们需要用的实例的时候,会调用getbean。
这样差不多,ioc,di就完成了

public class ApplicationContext {

    private String [] configLoactions;

    //bean的配置容器
    private final Map<String,BeanDefinition> beanDefinitionMap = new HashMap<String,BeanDefinition>();

    private BeanDefinitionReader reader;

    //真正的ioc容器
    private Map<String,BeanWrapper> factoryBeanInstanceCache = new HashMap<String,BeanWrapper>();

    private Map<String,Object> factoryBeanObjectCache = new HashMap<String, Object>();

    public ApplicationContext(String... configLocations){
        this.configLoactions = configLocations;
        try {
            //1读取配置文件
            reader =new BeanDefinitionReader(this.configLoactions);
            //2、解析配置文件,封装成BeanDefinition
            List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            //3、把BeanDefinition对应的实例放入
            doRegisterBeanDefinition(beanDefinitions);

             //4、完成依赖注入
            doAutowrited();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void doAutowrited() {
        //依赖注入的第一步
        //是不是先得根据配置把对象的实例搞出来,才有可能依赖注入
        for (Map.Entry<String,BeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();
            getBean(beanName);
        }
    }


    public Object getBean(String beanName){
        //1、读取GPBeanDefinition的配置信息
        BeanDefinition gpBeanDefinition = this.beanDefinitionMap.get(beanName);

        //2、用反射实例化
        Object instance = instantiateBean(beanName,gpBeanDefinition);

        //3、把创建出来的真实的实例包装为BeanWrapper对象
        BeanWrapper beanWrapper = new BeanWrapper(instance);

        //循环依赖
        //class A{B b;}
        //class B{A a;}
        //4、把BeanWrapper对象放入到真正的IOC容器里面
        this.factoryBeanInstanceCache.put(beanName,beanWrapper);

        //5、执行依赖注入
        populateBean(beanName,new BeanDefinition(),beanWrapper);
        return this.factoryBeanInstanceCache.get(beanName).getWrapperInstance();
    }


    public Properties getConfig(){
        return this.reader.getConfig();
    }
    private void populateBean(String beanName, BeanDefinition gpBeanDefinition, BeanWrapper beanWrapper) {
        Object instance = beanWrapper.getWrapperInstance();

        Class<?> clazz = beanWrapper.getWrappedClass();

        //只有加了注解的才进行依赖注入
        if(!(clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Service.class))){
            return;
        }

        //拿到实例的所有的字段
        //        //Declared 所有的,特定的 字段,包括private/protected/default
        //        //正常来说,普通的OOP编程只能拿到public的属性
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (!field.isAnnotationPresent(Autowired.class)) {
                continue;
            }
            Autowired autowired = field.getAnnotation(Autowired.class);
            //如果用户没有自定义beanName,默认就根据类型注入
            //这个地方省去了对类名首字母小写的情况的判断,这个作为课后作业
            //小伙伴们自己去完善
            String autowiredBeanName = autowired.value().trim();
            if ("".equals(autowiredBeanName)) {
                //获得接口的类型,作为key待会拿这个key到ioc容器中去取值
                autowiredBeanName = field.getType().getName();
            }

            //如果是public以外的修饰符,只要加了@Autowired注解,都要强制赋值
            //反射中叫做暴力访问, 强吻
            field.setAccessible(true);

            //反射调用的方式
            //给entry.getValue()这个对象的field字段,赋ioc.get(beanName)这个值
            try {
                if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) {
                    continue;
                }
                field.set(instance, this.factoryBeanInstanceCache.get(autowiredBeanName).getWrapperInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                continue;
            }
        }

    }
    private Object instantiateBean(String beanName, BeanDefinition gpBeanDefinition) {
                String className = gpBeanDefinition.getBeanClassName();
                Object instance = null;
                try {
                    Class<?> clazz = Class.forName(className);
                    instance = clazz.newInstance();
                    //1、读取通知和目标类的关联关系
                    AdvisedSupport config = instantionAopConfig(gpBeanDefinition);
                    config.setTargetClass(clazz);
                    config.setTarget(instance);
                   // /2、生成一个代理类
                    //不是所有的类都会生成代理类
                    if(config.pointCutMatch()) {
                        instance = new JdkDynamicAopProxy(config).getProxy();
                    }
                    this.factoryBeanObjectCache.put(beanName,instance);
//            this.factoryBeanObjectCache.put(gpBeanDefinition.getFactoryBeanName(),instance);
        }catch (Exception e){
            e.printStackTrace();
        }
        return instance;
    }
    private AdvisedSupport instantionAopConfig(BeanDefinition gpBeanDefinition) {
        AopConfig config = new AopConfig();
        config.setPointCut(this.reader.getConfig().getProperty("pointCut"));
        config.setAspectClass(this.reader.getConfig().getProperty("aspectClass"));
        config.setAspectBefore(this.reader.getConfig().getProperty("aspectBefore"));
        config.setAspectAfter(this.reader.getConfig().getProperty("aspectAfter"));
        config.setAspectAfterThrow(this.reader.getConfig().getProperty("aspectAfterThrow"));
        config.setAspectAfterThrowingName(this.reader.getConfig().getProperty("aspectAfterThrowingName"));
        return new AdvisedSupport(config);
    }

    private void doRegisterBeanDefinition(List<BeanDefinition> beanDefinitions) throws Exception{
        for (BeanDefinition beanDefinition : beanDefinitions) {
            if(this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){
                throw new Exception("The " + beanDefinition.getFactoryBeanName() + " is exists");
            }
            this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);

           // this.beanDefinitionMap.put(beanDefinition.getBeanClassName(),beanDefinition);
        }
    }
    public int getBeanDefinitionCount(){
        return beanDefinitionMap.size();
    }

    //获得IOC容器中所有的beanName的名字
    public String[] getBeanDefinitionNames(){
        return beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);
    }

    public Object getBean(Class beanClass){
        return getBean(beanClass.getName());
    }

}
public class BeanDefinitionReader {
    private List<String> registryBeanClasses = new ArrayList<String>();
    private Properties contextConfig = new Properties();


    public BeanDefinitionReader(String[] configLoactions) {
        //直接从类路径下找到Spring主配置文件所在的路径
        //并且将其读取出来放到Properties对象中
        //相对于scanPackage=com.gupaoedu.demo 从文件中保存到了内存中
        InputStream inputStream=this.getClass().getClassLoader().getResourceAsStream(configLoactions[0].replaceAll("classpath:","")) ;
        try {
            contextConfig.load(inputStream);


        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (null!=inputStream){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        doScanner(contextConfig.getProperty("scanPackage"));

    }

    private void doScanner(String scanPackage) {
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
        File classPath = new File(url.getFile());

        for (File file : classPath.listFiles()) {

            if(file.isDirectory()){
                doScanner(scanPackage + "." + file.getName());
            }else {
                //变成包名.类名
                //Class.forname()
                if (!file.getName().endsWith(".class")) {  continue; }
                String className = scanPackage + "." + file.getName().replace(".class", "");
                //classNames.add();
                registryBeanClasses.add(className);
            }
        }

    }


    private String toLowerFirstCase(String simpleName) {
        char [] chars = simpleName.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    public List<BeanDefinition> loadBeanDefinitions() {
        List<BeanDefinition>  beanDefinitions=new ArrayList<>();
        try {
            for (String className : registryBeanClasses) {
                Class<?> beanClass = Class.forName(className);
                if (beanClass.isInterface()){continue;}

                //1、默认类名首字母小
                // 2、自定义名字
                beanDefinitions.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()),beanClass.getName()));

                //3、接口注入
                for (Class<?> i : beanClass.getInterfaces()) {
                    beanDefinitions.add(doCreateBeanDefinition(i.getName(),beanClass.getName()));
                }


            }
        }catch (Exception e){
            e.printStackTrace();
        }


        return beanDefinitions;
    }


    private BeanDefinition doCreateBeanDefinition(String fatoryBeanName, String beanClassName) {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClassName(beanClassName);
        beanDefinition.setFactoryBeanName(fatoryBeanName);
        return beanDefinition;
    }

    public Properties getConfig() {
        return contextConfig;
    }
}

我们再来完成mvc

核心类:DispatcherServlet
处理URL 与方法的绑定:

public class HandlerMapping {
    protected Object controller;	//保存方法对应的实例
    protected Method method;		//保存映射的方法
    protected Pattern pattern;  

每个hander对应的参数处理器: HandlerAdapter,处理完后返回 ModelAndView

ModelAndView:方法返回包装类型
view:将数据处理模板文件板文件,读取,替换,然后返回给浏览器
ViewResolver:视图解析器,根据返回的约定,找到对应的ht模板文件给view

先提思路,然后直接上代码。

public class DispatcherServlet  extends HttpServlet {


    ApplicationContext applicationContext = null;
    //保存url和Method的对应关系
    private List<HandlerMapping> handlerMappings = new ArrayList<HandlerMapping>();

    //
    private Map<HandlerMapping,HandlerAdapter> handlerAdapters = new HashMap<HandlerMapping, HandlerAdapter>();


    private List<ViewResolver> viewResolvers = new ArrayList<ViewResolver>();

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //6、根据url调用method
        try {
           doDispatch(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
            resp.getWriter().write("500 Exception,Detail: " + Arrays.toString(e.getStackTrace()));
        }

    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        //1、根据url拿到对应的Handler
        HandlerMapping handler = getHandler(req);

        if(null == handler){
            processDispatchResult(req,resp,new ModelAndView("404"));
            return;
        }
        //2、根据HandlerMapping拿到HandlerAdapter
        HandlerAdapter ha = getHandlerAdapter(handler);

        //3、根据HandlerApdater拿到ModelAndView
        ModelAndView mv = ha.handle(req,resp,handler);

        //4、ViewResolver 拿到View
        //将View 渲染成浏览器能够接收的结果   HTML字符串
        processDispatchResult(req,resp,mv);


    }

    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, ModelAndView mv) throws Exception {
        if(null == mv){return;}
        if(this.viewResolvers.isEmpty()){return;}
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(mv.getViewName());
            view.render(mv.getModel(),req,resp);
            return;
        }

    }

    private HandlerAdapter getHandlerAdapter(HandlerMapping handler) {
        if(this.handlerAdapters.isEmpty()){return null;}
        HandlerAdapter ha = this.handlerAdapters.get(handler);
        return ha;
    }

    private HandlerMapping getHandler(HttpServletRequest req) {
          if (this.handlerMappings.isEmpty()){return null;}
        String url=req.getRequestURI();
        String contextPath=req.getContextPath();
        url = url.replaceAll(contextPath,"").replaceAll("/+","/");
        for (HandlerMapping handlerMapping : this.handlerMappings) {
            Matcher matcher = handlerMapping.getPattern().matcher(url);
            //url是用正则去匹配Controller中的配置信息
            if(!matcher.matches()){continue;}
            return handlerMapping;
        }
         return null;
    }


    public void init(ServletConfig config) throws ServletException {
        applicationContext = new ApplicationContext(config.getInitParameter("contextConfigLocation"));

        //初始化Spring MVC的九大组件,今天只实现
        //HandlerMapping
        //HandlerAdapter
        //ViewResolver
        initStrategies(applicationContext);
        System.out.println("GP Spring framework is init.");
    }

    private void initStrategies(ApplicationContext context) {
        //Url和Method的对应关系
        initHandlerMappings(context);
        //参数适配器
        initHandlerAdaters(context);

        //视图转换器
        initViewResolvers(context);

    }

    private void initViewResolvers(ApplicationContext context) {
        String templateRoot = context.getConfig().getProperty("templateRoot");
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();

        File templateRootDir = new File(templateRootPath);
        for (File file : templateRootDir.listFiles()) {
            //高仿真
            this.viewResolvers.add(new ViewResolver(templateRoot));
        }
    }

    private void initHandlerMappings(ApplicationContext context) {
        String [] beanNames = context.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            Object instance = context.getBean(beanName);
            Class<?> clazz = instance.getClass();
            if (!clazz.isAnnotationPresent(Controller.class)) {
                continue;
            }

            //保存写在类上面的@GPRequestMapping("/demo")
            String baseUrl = "";
            if(clazz.isAnnotationPresent(RequestMapping.class)){
                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                baseUrl = requestMapping.value();
            }

            //默认获取所有的public方法
            for (Method method : clazz.getMethods()) {
                if(!method.isAnnotationPresent(RequestMapping.class)){continue;}

                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);

                //demoquery
                //  //demo//query
                String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+","/");

                Pattern pattern = Pattern.compile(regex);
                this.handlerMappings.add(new HandlerMapping(instance,method,pattern));

                System.out.println("Mapped " + regex + "," + method);
            }

        }

    }


    private void initHandlerAdaters(ApplicationContext context) {
        for (HandlerMapping handlerMapping : handlerMappings) {
            this.handlerAdapters.put(handlerMapping,new HandlerAdapter());
        }
    }
}
public class HandlerAdapter {

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, HandlerMapping handler) throws Exception{

        //拼接形参列表
        //保存了Controller的方法上配置的参数名字以及和参数位置的对应关系
        Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();

        //提取方法中加了注解的参数
        Annotation[] [] pa = handler.getMethod().getParameterAnnotations();
        for (int i = 0; i < pa.length ; i ++) {
            for(Annotation a : pa[i]){
                if(a instanceof RequestParam){
                    String paramName = ((RequestParam) a).value();
                    if(!"".equals(paramName.trim())){
                        paramIndexMapping.put(paramName, i);
                    }
                }
            }
        }

        //提取方法中的request和response参数
        Class<?> [] paramsTypes = handler.getMethod().getParameterTypes();
        for (int i = 0; i < paramsTypes.length ; i ++) {
            Class<?> type = paramsTypes[i];
            if(type == HttpServletRequest.class ||
                    type == HttpServletResponse.class){
                paramIndexMapping.put(type.getName(),i);
            }
        }

        //拼接实参列表

        Map<String,String[]> paramsMap = request.getParameterMap();

        Object [] parameValues = new Object[paramsTypes.length];

        for (Map.Entry<String, String[]> param : paramsMap.entrySet()) {
            String value = Arrays.toString(paramsMap.get(param.getKey()))
                    .replaceAll("\\[|\\]","")
                    .replaceAll("\\s",",");
            if(!paramIndexMapping.containsKey(param.getKey())){continue;}

            int index = paramIndexMapping.get(param.getKey());
            parameValues[index] = caseStringValue(value,paramsTypes[index]);
        }

        if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
            int index = paramIndexMapping.get(HttpServletRequest.class.getName());
            parameValues[index] = request;
        }

        if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
            int index = paramIndexMapping.get(HttpServletResponse.class.getName());
            parameValues[index] = response;
        }


        Object result = handler.getMethod().invoke(handler.getController(),parameValues);
        if(result == null || result instanceof Void){return null;}

        boolean isModelAndView = handler.getMethod().getReturnType() == ModelAndView.class;
        if(isModelAndView){
            return (ModelAndView)result;
        }
        return null;
    }

    private Object caseStringValue(String value,Class<?> paramType){
        if(String.class == paramType){
            return value;
        }
        if(Integer.class == paramType){
            return Integer.valueOf(value);
        }else if(Double.class == paramType){
            return Double.valueOf(value);
        } else{
            if(value != null){
                return value;
            }
            return null;
        }
    }


package com.itwcxing.spring.framework.servlet;

import java.io.File;

/**
 * @Filename
 * @auther 吴星辰;
 * @data 2020/2/10 16:17;
 * @Descripion
 * @Version 1.1.1
 * @Function
 * @History
 */
public class ViewResolver {
    //.jsp   .vm    .ftl
    private final String DEAULT_TEMPLATE_SUFFX = ".html";

    private File templateRootDir;

    public ViewResolver(String teamplateRoot){
        String templateRootPath = this.getClass().getClassLoader().getResource(teamplateRoot).getFile();
        templateRootDir = new File(templateRootPath);
    }


    public View resolveViewName(String viewName){
        if(null == viewName || "".equals(viewName.trim())){return  null;}

        viewName = viewName.endsWith(DEAULT_TEMPLATE_SUFFX) ? viewName : (viewName + DEAULT_TEMPLATE_SUFFX);
        File templateFile = new File((templateRootDir.getPath() + "/" + viewName).replaceAll("/+","/"));
        return new View(templateFile);
    }


}


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Filename
 * @auther 吴星辰;
 * @data 2020/2/10 16:59;
 * @Descripion
 * @Version 1.1.1
 * @Function
 * @History
 */
public class View {

    private File viewFile;

    public View(File templateFile) {
        this.viewFile = templateFile;
    }

    public void render(Map<String,?> model, HttpServletRequest request, HttpServletResponse response) throws Exception{

        //第一步,就是把模板文件的内容读出来
        StringBuffer sb = new StringBuffer();
        RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");

        //解析,把模板里面写的模板语言替换掉
        String line = null;
        while (null != (line = ra.readLine())){
            line = new String(line.getBytes("ISO-8859-1"),"utf-8");
            Pattern pattern = Pattern.compile("¥\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE); //将 { 中不包含 } }  的逐个匹配
            Matcher mather = pattern.matcher(line);
            while (mather.find()){
                String paramName = mather.group();
                paramName = paramName.replaceAll("¥\\{|\\}","");//将 ¥ {   } 替换调
                Object paramVlue = model.get(paramName);
                if(null == paramVlue){continue;}
                line = mather.replaceFirst(makeStringForRegExp(paramVlue.toString()));
                mather = pattern.matcher(line);
            }
            sb.append(line);
        }

        response.setCharacterEncoding("utf-8");
        response.getWriter().write(sb.toString());
    }


    //处理特殊字符
    public static String makeStringForRegExp(String str) {
        return str.replace("\\", "\\\\").replace("*", "\\*")
                .replace("+", "\\+").replace("|", "\\|")
                .replace("{", "\\{").replace("}", "\\}")
                .replace("(", "\\(").replace(")", "\\)")
                .replace("^", "\\^").replace("$", "\\$")
                .replace("[", "\\[").replace("]", "\\]")
                .replace("?", "\\?").replace(",", "\\,")
                .replace(".", "\\.").replace("&", "\\&");
    }
}

再来写一下aop:

首先可以明确的知道
首先我们知道aop就是在加入ioc容器之前完成的,所以基本的思路就有了
在我们反射生成实例加入ioc的时候,判断一下这个方法需不需aop处理就行了。

先来介绍一下我们的类:
AdvisedSupport:处理配置信息和用来处理实际方法与通知先关起来
JdkDynamicAopProxy:实现jdbc代理

流程;
加入ioc容器前,生成AdvisedSupport对象并且导入advisrconfig
配置,目标实例,与类类,并生成正则判断。

然后直接正则判断是不是要aop的类。
如果是 生成目标方法和所有的切入方法对应关系。 jdbc一波就行

//1、读取通知和目标类的关联关系
GPAdvisedSupport config = instantionAopConfig(gpBeanDefinition);
config.setTargetClass(clazz);
config.setTarget(instance);
//2、生成一个代理类
//不是所有的类都会生成代理类
if(config.pointCutMatch()) {
    instance = new GPJdkDynamicAopProxy(config).getProxy();
}
public class GPAdvisedSupport {
    private Class targetClass;
    private Object target;
    private GPAopConfig config;
    private Pattern pointCutClassPattern;

    //用来保存配置文件中对应的Method和Advice的对应关系
    private Map<Method,Map<String,GPAdvice>> methodCache;

    public GPAdvisedSupport(GPAopConfig config) {
        this.config = config;
    }

    public Class getTargetClass() {
        return targetClass;
    }

    public void setTargetClass(Class targetClass) {
        this.targetClass = targetClass;
        parse();
    }

    private void parse() {
        //PonintCut  表达式解析为正则表达式
        String pointCut = config.getPointCut()
                .replaceAll("\\.","\\\\.")
                .replaceAll("\\\\.\\*",".*")
                .replaceAll("\\(","\\\\(")
                .replaceAll("\\)","\\\\)");

        //玩正则
        String pointCutForClassRegex = pointCut.substring(0,pointCut.lastIndexOf("\\(") - 4);
        pointCutClassPattern = Pattern.compile("class " + pointCutForClassRegex.substring(
                pointCutForClassRegex.lastIndexOf(" ") + 1));

        try {
            methodCache = new HashMap<Method, Map<String, GPAdvice>>();
            Pattern pointCutPattern = Pattern.compile(pointCut);

            Class apectClass = Class.forName(this.config.getAspectClass());
            Map<String,Method> aspectMethods = new HashMap<String,Method>();
            for (Method method : apectClass.getMethods()) {
                aspectMethods.put(method.getName(),method);
            }

            //循环找到所有的方法
            for (Method method : this.targetClass.getMethods()) {
                //保存方法名
                String methodString = method.toString();
                if(methodString.contains("throws")){
                    methodString = methodString.substring(0,methodString.lastIndexOf("throws")).trim();
                }
                Matcher matcher = pointCutPattern.matcher(methodString);
                if(matcher.matches()){
                    Map<String,GPAdvice> advices = new HashMap<String,GPAdvice>();

                    if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))){
                        advices.put("before",new GPAdvice(apectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));
                    }

                    if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))){
                        advices.put("after",new GPAdvice(apectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));
                    }

                    if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))){
                        GPAdvice a =  new GPAdvice(apectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow()));
                        a.setThrowName(config.getAspectAfterThrowingName());
                        advices.put("afterThrow",a);
                    }

                    methodCache.put(method,advices);
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public Object getTarget() {
        return target;
    }

    public boolean pointCutMatch() {
        return pointCutClassPattern.matcher(this.targetClass.toString()).matches();
    }

    public Map<String,GPAdvice> getAdivces(Method method, Class<?> targetClass) throws Exception{
        Map<String,GPAdvice> cached = methodCache.get(method);

        //精髓
        //如果没找到,就返回自己
        if(null == cached){
            Method m = targetClass.getMethod(method.getName(),method.getParameterTypes());
            cached = methodCache.get(m);
            this.methodCache.put(m,cached);
        }
        return cached;
    }

    public void setTarget(Object target) {
        this.target = target;
    }
package com.gupaoedu.vip.spring.framework.aop;

import com.gupaoedu.vip.spring.framework.aop.aspect.GPAdvice;
import com.gupaoedu.vip.spring.framework.aop.support.GPAdvisedSupport;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * Created by Tom.
 */
public class GPJdkDynamicAopProxy implements InvocationHandler {
    private GPAdvisedSupport config;
    public GPJdkDynamicAopProxy(GPAdvisedSupport config) {
        this.config = config;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.geetClass().getClassLoader(),this.config.getTargetClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Map<String,GPAdvice> advices = this.config.getAdivces(method,this.config.getTargetClass());
        Object returnValue = null;
        invokeAdivce(advices.get("before"));
        try {
            returnValue = method.invoke(this.config.getTarget(), args);
        }catch (Exception e){
            invokeAdivce(advices.get("afterThrow"));
            e.printStackTrace();
            throw e;
        }
        invokeAdivce(advices.get("after"));
        return returnValue;
    }

    private void invokeAdivce(GPAdvice advice) {
        try {
            advice.getAdviceMethod().invoke(advice.getAspect());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值