Spring框架进阶Spring V2.0 IOC与DI

Posted 烟锁迷城

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架进阶Spring V2.0 IOC与DI相关的知识,希望对你有一定的参考价值。

1、IOC的本质

Map 容器:IOC容器的本质就是一个Map

ApplicationContext 上下文:持有BeanFactory的引用

BeanFactory 工厂:负责从容器中获取Bean

BeanDefinitionReader 解析器:负责解析全部的配置文件

Definition 元信息配置:xml,yml,annotation,properties,为了适配各种不同的配置文件,Spring采用顶层设计BeanDefinition来保存配置信息。

Bean 实例:反射实例化Bean。这个Bean的来源可能是原生Bean,可能是代理Bean,无论是哪一种Bean,都会被BeanWrapper进行装饰(装饰器模式),它持有Bean的引用。

BeanWrapper 装饰器:缓存到IOC容器中,持有Bean的引用

通过ApplicationContext调用getBean()方法来获得各种BeanFactory ,通过BeanDefinitionReader读取配置文件信息,根据BeanDefinition创建Bean,得到的Bean无论是原生对象还是代理对象,都交给BeanWrapper进行装饰,所以getBean()方法,最后拿到的就是BeanWrapper对象

 2、从Servlet到ApplicationContext

在上一篇文章中,以MyDispatchServlet为基准实现了一个简单的Spring框架流程:

  1. 读取配置文件
  2. 根据包地址扫描文件
  3. 初始化IOC容器,实例化Bean,加载至IOC中
  4. 依赖注入
  5. 匹配URL和方法,存放到HandlerMapping

1·4步骤,都是IOC与DI的操作,都是需要转化到ApplicationContext之中的步骤。

新的步骤为:

  1. 读取配置文件,扫描对应的包下的文件
  2. 获取到所有配置信息
  3. 将所有配置信息保存
  4. 加载所有非延迟加载Bean

执行加载Bean的方法就是Spring框架的核心方法,getBean方法,其步骤为:

  1. 根据BeanName获取配置信息
  2. 实例化Instance
  3. 将Instance封装到BeanWrapper中
  4. 对Instance进行依赖注入
  5. 将Instance加载到IOC中

3、与Spring源码的结合

为了实现功能,需要结合Spring源码进行一些分析。

BeanFactory是核心,它具有一个关键的方法,getBean。

其中ApplicationContext类,DefaultListableBeanFactory类都继承了BeanFactory。

DefaultListableBeanFactory的作用是保存了所有的配信息:beanDefinitionMap,三级缓存(即IOC的终极缓存):factoryBeanInstanceCache,所有Bean的类备份:factoryBeanObjectCache,并且实现了getBean方法

ApplicationContext持有DefaultListableBeanFactory的引用,因此可以通过使用DefaultListableBeanFactory的一些数据完成方法。

BeanDefinitionReader类是专门用来读取配置文件和扫描包下文件。

BeanDefinition用来保存bean的名字:factoryBeanName,bean的全类名:beanClassName

BeanWrapper用来封装实例化的bean,最后保存到IOC中,其中包括实例对象:wrappedInstance,类对象:wrappedClass。

了解到这些主要的类,就可以开始进行代码的编写了。

4、实现过程

4.1、ApplicationContext部分

4.1.1、对象工厂

/**
 * 创建对象的工厂
 */
public interface MyBeanFactory 

    Object getBean(Class beanClass);

    Object getBean(String beanName);

4.1.2、读取配置文件并扫描包

在ApplicationContext的构造函数中,执行BeanDefinitionReader的创建以加载配置文件

public class MyApplicationContext implements MyBeanFactory 

    //持有引用
    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    //配置文件读取器
    private MyBeanDefinitionReader reader = null;

    public MyApplicationContext(String... configLocations) 
        //1、加载配置文件
        reader = new MyBeanDefinitionReader(configLocations);
    

BeanDefinitionReader类拥有Properties和registryBeanClasses,这两个容器不必赘述,在上一篇中已经出现过

public class MyBeanDefinitionReader 

    //配置文件信息
    private Properties contextConfig = new Properties();
    //注册文件名集合
    private List<String> registryBeanClasses = new ArrayList<String>();

    public MyBeanDefinitionReader(String... locations) 
        //1、加载配置文件
        doLoadConfig(locations[0]);
        //2、扫描相关的类
        doScanner(contextConfig.getProperty("scanPackage"));
    

这两个方法的实现也和上一篇文章中的实现方式并无差异。

private void doLoadConfig(String configLocation) 
    InputStream stream = this.getClass().getClassLoader().getResourceAsStream(configLocation.replaceAll("classpath:", ""));
    try 
        contextConfig.load(stream);
     catch (IOException e) 
        e.printStackTrace();
     finally 
        if (stream != null) 
            try 
                stream.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
    


private void doScanner(String scanPackage) 
    URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\\\.", "/"));
    File aFile = new File(url.getFile());
    for (File file : aFile.listFiles()) 
        String fileName = file.getName();
        if (file.isDirectory()) 
            doScanner(scanPackage + "." + fileName);
        
        if (!fileName.endsWith(".class")) 
            continue;
        
        String className = scanPackage + "." + fileName.replaceAll(".class", "");
        registryBeanClasses.add(className);
    

4.1.3、获取到所有配置信息

首先需要创建配置类BeanDefinition,里面具有

bean的名字:factoryBeanName

bean的全类名:beanClassName

是否延迟加载:getLazyInit()

public class MyBeanDefinition 

    //beanName
    private String factoryBeanName;
    //全类名
    private String beanClassName;

    public String getFactoryBeanName() 
        return factoryBeanName;
    

    public void setFactoryBeanName(String factoryBeanName) 
        this.factoryBeanName = factoryBeanName;
    

    public String getBeanClassName() 
        return beanClassName;
    

    public void setBeanClassName(String beanClassName) 
        this.beanClassName = beanClassName;
    

    //是否延时加载
    public boolean isLazyInit() 
        return false;
    

在ApplicationContext文件中,增加一个步骤:

public class MyApplicationContext implements MyBeanFactory 

    //持有引用
    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    //配置文件读取器
    private MyBeanDefinitionReader reader = null;

    public MyApplicationContext(String... configLocations) 
        //1、加载配置文件
        reader = new MyBeanDefinitionReader(configLocations);
        try 
            //2、解析配置文件,将配置信息封装成BeanDefinition对象
            List<MyBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
         catch (Exception e) 
            e.printStackTrace();
        
    

可以发现,这里的方法loadBeanDefinition类似于上一章的实例化过程,只不过这次保存的是bean对象的bean名与bean全名。

public List<MyBeanDefinition> loadBeanDefinitions() 
    List<MyBeanDefinition> result = new ArrayList<MyBeanDefinition>();
    try 
        for (String beanName : registryBeanClasses) 
            Class<?> aClass = Class.forName(beanName);
            if (aClass.isInterface()) 
                continue;
            
            result.add(createBeanDefinition(toLowerFirstCase(aClass.getSimpleName()), aClass.getName()));
            for (Class<?> anInterface : aClass.getInterfaces()) 
                result.add(createBeanDefinition(anInterface.getName(), aClass.getName()));
            
        
     catch (Exception e) 
        e.printStackTrace();
    
    return result;


private MyBeanDefinition createBeanDefinition(String factoryBeanName, String beanClassName) 
    MyBeanDefinition beanDefinition = new MyBeanDefinition();
    beanDefinition.setFactoryBeanName(factoryBeanName);
    beanDefinition.setBeanClassName(beanClassName);
    return beanDefinition;


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

4.1.4、保存配置信息至DefaultListableBeanDefinition

在ApplicationContext中继续添加步骤:

public class MyApplicationContext implements MyBeanFactory 

    //持有引用
    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    //配置文件读取器
    private MyBeanDefinitionReader reader = null;

    public MyApplicationContext(String... configLocations) 
        //1、加载配置文件
        reader = new MyBeanDefinitionReader(configLocations);
        try 
            //2、解析配置文件,将配置信息封装成BeanDefinition对象
            List<MyBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            //3、把所有配置信息缓存
            this.registry.doRegistryBeanDefinition(beanDefinitions);
         catch (Exception e) 
            e.printStackTrace();
        
    

 方法doRegistryBeanDefinition,简单理解就是进行配置信息的注册,即将BeanDefinition列表转移到BeanDefinitionMap之中,其key为factoryBeanName,value为BeanDefinition。

public class MyDefaultListableBeanFactory implements MyBeanFactory 

    //保存所有的配置信息
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<String, MyBeanDefinition>();

    //三级缓存,也是终极缓存
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<String, MyBeanWrapper>();

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

    public void doRegistryBeanDefinition(List<MyBeanDefinition> beanDefinitions) throws Exception 
        for (MyBeanDefinition beanDefinition : beanDefinitions) 
            if (beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())) 
                throw new Exception("已经存在" + beanDefinition.getFactoryBeanName());
            
            beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition);
        
    

4.1.5、加载非延时Bean

在ApplicationContext中,继续添加步骤:

public class MyApplicationContext implements MyBeanFactory 

    //持有引用
    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    //配置文件读取器
    private MyBeanDefinitionReader reader = null;

    public MyApplicationContext(String... configLocations) 
        //1、加载配置文件
        reader = new MyBeanDefinitionReader(configLocations);
        try 
            //2、解析配置文件,将配置信息封装成BeanDefinition对象
            List<MyBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            //3、把所有配置信息缓存
            this.registry.doRegistryBeanDefinition(beanDefinitions);
            //4、加载所有非延时加载的bean
            doLoadInstance();
         catch (Exception e) 
            e.printStackTrace();
        
    

根据从DefaultListableBeanDefinition中获取的配置文件信息,可以以循环的方式完成bean的加载,使用的方法也是getBean。这里的getBean可以使用ApplicationContext的方法,因为继承了BeanFactory。

但是DefaultListableBeanDefinition也继承了BeanFactory,而且其中还包含三级缓存和Bean的实例保存,且ApplicationContext持有DefaultListableBeanDefinition的引用,所以Spring源码里的getBean是DefaultListableBeanDefinition实现的,ApplicationContext只需要引用其方法即可。

    private void doLoadInstance() 
        //循环调用getBean方法
        for (Map.Entry<String, MyBeanDefinition> entry : this.registry.beanDefinitionMap.entrySet()) 
            String beanName = entry.getKey();
            //是否延时加载,如果非延时,则立刻加载
            if (!entry.getValue().isLazyInit()) 
                getBean(beanName);
            
        
    

4.2、DefaultListableBeanDefinition部分

其实DefaultListableBeanDefinition部分只剩下getBean的实现了。

根据上述过的步骤,进行编写

4.2.1、获取配置信息

DefaultListableBeanDefinition类的步骤:

public class MyDefaultListableBeanFactory implements MyBeanFactory 

    //保存所有的配置信息
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<String, MyBeanDefinition>();

    //三级缓存,也是终极缓存
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<String, MyBeanWrapper>();

    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();
    
    @Override
    public Object getBean(String beanName) 
        //1、先拿到对应的beanDefinition配置信息
        MyBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        return null;
    

4.2.2、实例化类

添加DefaultListableBeanDefinition类的步骤:

public class MyDefaultListableBeanFactory implements MyBeanFactory 

    //保存所有的配置信息
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<String, MyBeanDefinition>();

    //三级缓存,也是终极缓存
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<String, MyBeanWrapper>();

    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();
    
    @Override
    public Object getBean(String beanName) 
        //1、先拿到对应的beanDefinition配置信息
        MyBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        //2、反射实例化对象
        Object instance = instantiateBean(beanName, beanDefinition);
        return null;
    

方法instantiateBean调用反射进行实例化,并将实例化内容保存到factoryBeanObjectCache

private Object instantiateBean(String beanName, MyBeanDefinition beanDefinition) 
    String beanClassName = beanDefinition.getBeanClassName();
    Object instance = null;
    try 
        Class<?> aClass = Class.forName(beanClassName);
        instance = aClass.newInstance();
        //如果是代理对象,将触发AOP代理

        this.factoryBeanObjectCache.put(beanName, instance);
     catch (Exception e) 
        e.printStackTrace();
    
    return instance;

4.2.3、封装BeanWrapper

添加DefaultListableBeanDefinition类的步骤:

public class MyDefaultListableBeanFactory implements MyBeanFactory 

    //保存所有的配置信息
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<String, MyBeanDefinition>();

    //三级缓存,也是终极缓存
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<String, MyBeanWrapper>();

    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();
    
    @Override
    public Object getBean(String beanName) 
        //1、先拿到对应的beanDefinition配置信息
        MyBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        //2、反射实例化对象
        Object instance = instantiateBean(beanName, beanDefinition);
        //3、将返回的对象封装成BeanWrapper
        MyBeanWrapper beanWrapper = new MyBeanWrapper(instance);
        return null;
    

创建BeanWrapper,需要两个属性

实例化的类:wrappedInstance

实例化类的Class:wrappedClass

public class MyBeanWrapper 

    private Object wrappedInstance;
    private Class<?> wrappedClass;

    public MyBeanWrapper(Object instance) 
        this.wrappedInstance = instance;
        this.wrappedClass = instance.getClass();
    

    public Object getWrappedInstance() 
        return this.wrappedInstance;
    

    public Class<?> getWrappedClass() 
        return this.wrappedClass;
    

 只需要构造函数进行初始化即可

4.2.4、依赖注入

添加DefaultListableBeanDefinition类的步骤:

public class MyDefaultListableBeanFactory implements MyBeanFactory 

    //保存所有的配置信息
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<String, MyBeanDefinition>();

    //三级缓存,也是终极缓存
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<String, MyBeanWrapper>();

    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();
    
    @Override
    public Object getBean(String beanName) 
        //1、先拿到对应的beanDefinition配置信息
        MyBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        //2、反射实例化对象
        Object instance = instantiateBean(beanName, beanDefinition);
        //3、将返回的对象封装成BeanWrapper
        MyBeanWrapper beanWrapper = new MyBeanWrapper(instance);
        //4、执行依赖注入
        populateBean(beanName, beanDefinition, beanWrapper);
        return null;
    

方法populateBean生成bean,这个方法和之前的依赖注入并无太大区别,无需赘述

private void populateBean(String beanName, MyBeanDefinition beanDefinition, MyBeanWrapper beanWrapper) 
    Object instance = beanWrapper.getWrappedInstance();
    Class<?> clazz = instance.getClass();
    if (!(clazz.isAnnotationPresent(MyController.class) || clazz.isAnnotationPresent(MyService.class))) 
        return;
    
    for (Field field : clazz.getDeclaredFields()) 
        if (!field.isAnnotationPresent(MyAutowired.class)) 
            continue;
        
        MyAutowired autowired = field.getAnnotation(MyAutowired.class);
        String autowiredBeanName = field.getType().getName();
        if (!"".equals(autowired.value())) 
            autowiredBeanName = autowired.value().trim();
        
        field.setAccessible(true);
        try 
            if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) 
                continue;
            
            field.set(instance, this.factoryBeanInstanceCache.get(autowiredBeanName).getWrappedInstance());
         catch (IllegalAccessException e) 
            e.printStackTrace();
        
    

4.2.5、IOC装载

添加DefaultListableBeanDefinition类的步骤:

public class MyDefaultListableBeanFactory implements MyBeanFactory 

    //保存所有的配置信息
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<String, MyBeanDefinition>();

    //三级缓存,也是终极缓存
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<String, MyBeanWrapper>();

    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();
    
    @Override
    public Object getBean(String beanName) 
        //1、先拿到对应的beanDefinition配置信息
        MyBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        //2、反射实例化对象
        Object instance = instantiateBean(beanName, beanDefinition);
        //3、将返回的对象封装成BeanWrapper
        MyBeanWrapper beanWrapper = new MyBeanWrapper(instance);
        //4、执行依赖注入
        populateBean(beanName, beanDefinition, beanWrapper);
        //5、保存到IOC容器中
        this.factoryBeanInstanceCache.put(beanName, beanWrapper);
        return beanWrapper.getWrappedInstance();
    

 这里的步骤就是将最后的封装结果放入IOC,即三级缓存factoryBeanInstanceCache中。

4.3、DispatchServlet的部分

完成ApplicationContext的构建之后,就可以去掉那些不必要的步骤,以ApplicationContext进行代替。

public class MyDispatchServlet extends HttpServlet 

    private Map<String, Method> handlerMapping = new HashMap<String, Method>();
    private MyApplicationContext myApplicationContext = null;

    @Override
    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 
        try 
            doDispatch(req, resp);
         catch (Exception e) 
            e.printStackTrace();
        
    

    @Override
    public void init(ServletConfig config) throws ServletException 
        myApplicationContext = new MyApplicationContext(config.getInitParameter("contextConfigLocation"));
        doHandlerMapping();
    

没有了之前的IOC容器,很多判断就失去了依据,那么就需要从ApplicationContext中获取到有关于容器的内容

增加方法getBeanDefinitionCount,获取配置文件长度

增加方法getBeanDefinitionNames,获取配置文件的key,即bean的名字

public class MyApplicationContext implements MyBeanFactory 

    //持有引用
    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    //配置文件读取器
    private MyBeanDefinitionReader reader = null;

    public MyApplicationContext(String... configLocations) 
        //1、加载配置文件
        reader = new MyBeanDefinitionReader(configLocations);
        try 
            //2、解析配置文件,将配置信息封装成BeanDefinition对象
            List<MyBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            //3、把所有配置信息缓存
            this.registry.doRegistryBeanDefinition(beanDefinitions);
            //4、加载所有非延时加载的bean
            doLoadInstance();
         catch (Exception e) 
            e.printStackTrace();
        
    

    private void doLoadInstance() 
        //循环调用getBean方法
        for (Map.Entry<String, MyBeanDefinition> entry : this.registry.beanDefinitionMap.entrySet()) 
            String beanName = entry.getKey();
            //是否延时加载,如果非延时,则立刻加载
            if (!entry.getValue().isLazyInit()) 
                getBean(beanName);
            
        
    

    @Override
    public Object getBean(Class beanClass) 
        return this.getBean(beanClass.getName());
    

    @Override
    public Object getBean(String beanName) 
        return this.registry.getBean(beanName);
    

    public int getBeanDefinitionCount() 
        return this.registry.beanDefinitionMap.size();
    

    public String[] getBeanDefinitionNames() 
        return this.registry.beanDefinitionMap.keySet().toArray(new String[0]);
    

这样剩余的判断就有依据了

public class MyDispatchServlet extends HttpServlet 

    private Map<String, Method> handlerMapping = new HashMap<String, Method>();
    private MyApplicationContext myApplicationContext = null;

    @Override
    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 
        try 
            doDispatch(req, resp);
         catch (Exception e) 
            e.printStackTrace();
        
    

    @Override
    public void init(ServletConfig config) throws ServletException 
        myApplicationContext = new MyApplicationContext(config.getInitParameter("contextConfigLocation"));
        doHandlerMapping();
    

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws InvocationTargetException, IllegalAccessException, IOException 
        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 = handlerMapping.get(url);
        Map<String, Integer> paramMapping = new HashMap<String, Integer>();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) 
            for (Annotation annotation : parameterAnnotations[i]) 
                if (annotation instanceof MyRequestParam) 
                    String value = ((MyRequestParam) annotation).value();
                    if (!"".equals(value)) 
                        paramMapping.put(value, i);
                    
                
            
        
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) 
            Class<?> parameterType = parameterTypes[i];
            if (HttpServletRequest.class == parameterType || HttpServletResponse.class == parameterType) 
                paramMapping.put(parameterType.getName(), i);
            
        
        Object[] paramValues = new Object[paramMapping.size()];
        Map<String, String[]> params = req.getParameterMap();
        for (Map.Entry<String, String[]> param : params.entrySet()) 
            String value = Arrays.toString(param.getValue())
                    .replaceAll("\\\\[|\\\\]", "")
                    .replaceAll("\\\\s", "");
            if (!paramMapping.containsKey(param.getKey())) 
                continue;
            
            paramValues[paramMapping.get(param.getKey())] = value;
        

        if (paramMapping.containsKey(HttpServletRequest.class.getName())) 
            int index = paramMapping.get(HttpServletRequest.class.getName());
            paramValues[index] = req;
        

        if (paramMapping.containsKey(HttpServletResponse.class.getName())) 
            int index = paramMapping.get(HttpServletResponse.class.getName());
            paramValues[index] = resp;
        

        String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
        Object obj = myApplicationContext.getBean(beanName);
        method.invoke(obj, paramValues);
    

    private void doHandlerMapping() 
        if (myApplicationContext.getBeanDefinitionCount() == 0) 
            return;
        
        try 
            for (String beanName : myApplicationContext.getBeanDefinitionNames()) 
                Object instance = myApplicationContext.getBean(beanName);
                Class aClass = instance.getClass();
                if (!aClass.isAnnotationPresent(MyController.class)) 
                    continue;
                
                String url = "";
                if (aClass.isAnnotationPresent(MyRequestMapping.class)) 
                    MyRequestMapping myRequestMapping = (MyRequestMapping) aClass.getAnnotation(MyRequestMapping.class);
                    url = "/" + myRequestMapping.value();
                
                for (Method method : aClass.getMethods()) 
                    if (!method.isAnnotationPresent(MyRequestMapping.class)) 
                        continue;
                    
                    MyRequestMapping myRequestMapping = (MyRequestMapping) method.getAnnotation(MyRequestMapping.class);
                    handlerMapping.put((url + "/" + myRequestMapping.value()).replaceAll("/+", "/"), method);
                
            
         catch (Exception e) 
            e.printStackTrace();
        
    

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

全部完成后,执行,访问:http://localhost:8080/user/name?name=lily

以上是关于Spring框架进阶Spring V2.0 IOC与DI的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架进阶Spring V2.0 循环依赖

Spring框架进阶Spring V2.0 循环依赖

Spring框架进阶Spring V2.0 AOP

Spring框架进阶Spring V2.0 MVC

Spring框架进阶Spring V3.0 IOC源码分析流程

Spring框架进阶Spring V1.0