300行代码实现spring

1. 实现思路

在这里插入图片描述

2.常见面试问题

1.请用自己的语言描述SpringIOC、DI、MVC的基本执行原理。

  • IOC: Inversion of Control(控制反转),作为一个容器,用于保存spring管理的所有对象。
    目标:使用SpringIOC容器管理对象。
    既然已经有了明确的目标,下一步就应该开始将对象添加到IOC容器中。
    步骤:

    • 1)了解哪些对象需要被spring管理。doScanner方法:读取配置文件或者注解,找到开发者声明的需要依靠spring管理的类,扫描属性(例如 id class init- method scope),记录相应属性,以便DI时可以进行注入。
    • 2)将已了解到的需要交给Spring管理的类进行初始化。doInstance方法:按照扫描结果,将对象进行初始化优先使用之前扫描到,声明的beanName,若没有则使用类名首字母小写作为ioc容器中的key,保存到ioc容器中。
  • DI:Dependency Injection(依赖注入),需要使用在springIOC容器中的对象,需要在注解或者配置文声明,当对象之间有依赖关系时,可以利用spring保存的对象关系。
    目标:spring保存的对象依赖关系,将对象从IOC容器中取出,进行注入。
    既然已经有了明确的目标,下一步就应该从IOC容器中取出对象进行注入。
    步骤:

    • 1)判断哪些对象需要注入。
      方法:读取配置文件或者注解(Autowired),判断出需要哪些对象是需要注入的。
    • 2)怎么注入。
      方法:如果用户有声明beanName,直接从IOC容器中取出相应的对象进行注入,若没有,根据类型进行注入。(此处一个接口只能有一个实现类,若有多个,且都交由spring管理,且未制定beanName,则在IOC步骤就会报错)
  • MVC:Model-View-Controller, model:是指模型表示业务规则、View:是指用户看并与之交互的界面、controller:是指控制器接受用户的输入并调用模型和视图去完成用户的需求,MVC的目的:在于将M和V的实现代码分离。而Spring MVC其实做的就是存储url和Method的对应关系,实现传入url调用制定控制器,进行制定业务规则,返回相应的view。
    目标:存储url和Method的对应关系,实现传入url调用制定控制器,进行制定业务规则,返回相应的view。
    既然已经有了明确的目标,下面聊聊怎么实现。
    步骤:

    • 1)找到需要在handlerMapping中记录的类与方法
      方法:扫描注解或者配置文件,读取类以及方法的RequestMapping中的值
    • 2)将url和Method的对应关系存储到handlerMapping中
      方法:将类的RequestMapping的值+方法的RequestMapping的值拼接作为url,将url作Key,method作值,存储到handlerMapping
    • 3)用户调用
      基于serverlet的实现,在doPost()中执行doDispatch()方法,通过url从handlerMapping中找到指定的方法,使用反射进行调用。

2.Spring中的Bean是线程安全的吗?为什么?。

Spring中的Bean不保证线程安全。
在聊为什么之前,先谈一谈我的理解。
首先我们假定Spring中的Bean是线程安全的,spring需要如何保证Bean的线程安全。作为一个轻量级的框架,spring对于代码的侵入是非常少的,那么想要保证Bean的线程安全,唯一的做法就是在IOC端进行锁的控制。在从IOC容器获取对象之后,加锁。其他类想用?不好意思锁住了,想用就得等我执行完毕,由IOC容器回收,再释放锁之后,你再去抢锁。这样,一个类在执行,其他类就得看着。

这种操作,我认为Spring这么牛X的框架是不可能执行这么蠢的操作的。
那么这么牛X的框架又是怎么做的呢,在初学Spring时了解到作用域(scope)是一个非常重要的概念。spring中为Bean提供了多种作用域给用户做选择,用户可以自己根据业务场景来选择具体的Bean的作用域。并不是所有场景都需要线程安全的Bean的。
scope很好的解决的安全与速度的问题,将安全问题交由用户控制。
  1、singleton:单例,默认作用域。
  2、prototype:原型,每次创建一个新对象。
  3、request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
  4、session:会话,同一个会话共享一个实例,不同会话使用不用的实例。
  5、global-session:全局会话,所有会话共享一个实例。
对于平常写写增删改查涉及到的各种操作,基本涉及到的是无状态的Bean,不用管直接用就是,更本无需担心安全问题,速度也是快得不行。当是一个有状态的Bean,改变scope,用户可以自己来控制对象不会相互影响,在牺牲一部分速度的情况下,就能考虑安全。

package cn.javass.spring.chapter4; import java.io.File; import java.io.IOException; import junit.framework.Assert; import org.jboss.vfs.VFS; import org.jboss.vfs.VirtualFile; import org.jboss.vfs.spi.RealFileSystem; import org.junit.Test; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; @SuppressWarnings("all") public class ResourcePatternTest { @Test public void testClasspathPrefix() throws IOException { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //只加载一个绝对匹配Resource,且通过ResourceLoader.getResource进加载 Resource[] resources = resolver.getResources("classpath:META-INF/INDEX.LIST"); Assert.assertEquals(1, resources.length); //只加载一个匹配的Resource,且通过ResourceLoader.getResource进加载 resources = resolver.getResources("classpath:META-INF/*.LIST"); Assert.assertTrue(resources.length == 1); //只加载一个绝对匹配Resource,且通过ResourceLoader.getResource进加载 resources = resolver.getResources("classpath:META-INF/MANIFEST.MF"); Assert.assertEquals(1, resources.length); } @Test public void testClasspathAsteriskPrefix() throws IOException { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //将加载多个绝对匹配的所有Resource //将首先通过ClassLoader.getResources("META-INF")加载非模式路径部分 //然后进遍历模式匹配 Resource[] resources = resolver.getResources("classpath*:META-INF/INDEX.LIST"); Assert.assertTrue(resources.length > 1); //将加载多个模式匹配的Resource resources = resolver.getResources("classpath*:META-INF/*.LIST"); Assert.assertTrue(resources.length > 1); } @Test public void testClasspathAsteriskPrefixLimit() throws IOException { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //将首先通过ClassLoader.getResources("")加载目录, //将只返回文件系统的类路径不返回jar的跟路径 //然后进遍历模式匹配 Resource[] resources = resolver.getResources("classpath*:asm-*.txt"); Assert.assertTrue(resources.length == 0); //将通过ClassLoader.getResources("asm-license.txt")加载 //asm-license.txt存在于com.springsource.net.sf.cglib-2.2.0.jar resources = resolver.getResources("classpath*:asm-license.txt"); Assert.assertTrue(resources.length > 0); //将只加载文件系统类路径匹配的Resource resources = resolver.getResources("classpath*:LICENS*"); Assert.assertTrue(resources.length == 1); } @Test public void testFilekPrefix() throws IOException { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("file:D:/*.txt"); Assert.assertTrue(resources.length > 0); } @Test public void testVfsPrefix() throws IOException { //1.创建一个虚拟的文件目录 VirtualFile home = VFS.getChild("/home"); //2.将虚拟目录映射到物理的目录 VFS.mount(home, new RealFileSystem(new File("d:"))); //3.通过虚拟目录获取文件资源 VirtualFile testFile = home.getChild("test.txt"); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("/home/test.txt"); Assert.assertTrue(resources.length > 0); System.out.println(resources[0].getClass()); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值