本篇咱们就开始学习Java领域大名鼎鼎的Spring Framework,本篇介绍的Spring Framework中的IOC(控制反转,也称依赖注入),原本想用初遇篇,这个题目的,可是一想这个题目不太见名知义,就改为上柱国列传了。为何叫上柱国IOC列传呢,由于以为上柱国这个名字挺好听。
上柱国: 原义为自春秋起为军事武装的高级统帅,引伸义为功勋的荣誉称号,战国时楚、赵置,位令尹、相国下,甚尊。原为保卫国都之官
2002年 Rod Johnson在2002年编著的《Expert One-On-One J2EE Design And Development》一书中对,对Java EE正统框架(EJB)臃肿、低效、脱离现实的学院派提出了质疑,而后以该书为指导思想,编写了interface21框架。而后在interface21框架的基础上,通过从新设计,于2004年发布。到如今开始已经十八年左右了。java
在《欢迎光临Spring时代-绪论》中咱们提出了几个关于如何取对象的问题,这里咱们再回忆一下:正则表达式
在我刚学Spring框架的时候,很多视频都会说,咱们并不在new对象,而是将对象放进IOC容器中,你要取的时候,向IOC容器中取便可。这里咱们先从实例入手再来解释IOC。结合着例子来解释IOC会更加易懂。
本篇咱们还基于maven来作示例,基本上开发Spring Framework的程序基本上就只须要五个jar包就够了,分别是下面这五个:spring
此次咱们选的版本都是5.2.8.RELEASE。
若是你不会用maven,而后请参考个人这篇博客:express
若是暂时还不想学maven,还想作jar包下载。那么有两种形式能够下载到对应的jar包:segmentfault
浏览器访问这个网址: https://maven.springframework...
下载完粘贴到对应的lib目录下便可。数组
输入上面的jar包名字,粘贴对应的依赖便可。
开发工具我这里用的是IDEA,提示比较强大,用着比较顺手。
若是你不习惯用IDEA,是Eclipse党,这边推荐你下载Spring官方出品的开发工具STS,也是在Eclipse的基础开发的,开发Spring框架的程序更加快速。
浏览器输入: https://spring.io/tools/
![]()
本文的示例都是基于IDEA来作的,若是不会用IDEA,想用STS,能够参考文末后面的参考资料,是视频。
通常Spring框架的这个配置文件,咱们都命名为applicationContext.xml,这是一种大体的约定。
上面的问题是如何优雅的取对象,在取以前你首先就得存,向applicationContext.xml放对象。怎么放?
像下面这样放:
我建了一个Student类,而后里面有name和age属性,无参和有参构造函数,get和set函数,重写了toString方法。
bean里的id是惟一的,class是Student类的全类名(包名+类名)。
如何取:浏览器
public class SpringDemo { public static void main(String[] args) { // 加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = (Student) applicationContext.getBean("student"); System.out.println(student); } }
打印结果: springboot
咱们直接new,在Spring的配置文件配置参数,而后间接取对象的方式, 咱们称之为控制反转(IOC Inversion of Control)或依赖注入(DI Dependency Injection)。首先解释一下为何有两个称呼,刚开始是只有控制反转,后来发现控制反转这个概念有点难以理解,就在一次大会上讲控制反转改成依赖注入。
那什么是控制反转,咱们能够认为new 对象是一种控制权,而后控制反转就是咱们将new对象的控制权交给Spring Framework。依赖注入呢? 其实也是同样,咱们能够理解为在Spring的配置文件配置完对象以后,Spring将该对象给须要该对象的对象,此时就回答了上面咱们提出的第二个问题:session
对象之间有复杂的依赖关系的时候,在不但愿是硬编码的状况下,如何取对象才能作到优雅和可配置化?
若是对象之间有复杂的依赖关系,那么就请将这种复杂的依赖关系当作配置参数同样,放在Spring的配置文件中,而后再从Spring IOC容器中取值,咱们此时姑且就能够将配置文件当作IOC容器,放置了对象。
用上面的配置只能解决简单的值,那若是某个对象的某个属性也是对象类型的呢? Spring也想到了,当对象的属性是属性用ref注入,像下面这样:app
<bean id = "studentCard" class = "org.example.StudentCard"> <property name = "id" value="1"></property> <property name = "cardNo" value="code01"></property> </bean> <bean id="student" class="org.example.Student"> <property name = "name" value = "zs"></property> <property name = "age" value = "23"></property> <property name = "studentCard" ref = "studentCard"></property> </bean>
普通属性用value,那么引用类型就用ref,ref的值是配置文件中bean标签的id属性,因此在applicationContext.xml中id禁止重复。
咱们上面的第三个问题,咱们Dao层的对象在对应的Service只须要一份就能够了,Spring容器中的对象默认都是单例的。
那Dao层有的时候都没有属性,咱们还要写在配置文件中吗?Spring也想到了,提供了下面几个注解:
@Controller 对应控制层 @Service 对应服务层 @Component 通用注解,若是你不肯定这个对象属于那一层的话,就用这个。 @Repository 对应dao层
而后在配置文件中加入:
<!--配置扫描器,base-package放须要扫描的包,指定了包以后,Spring会扫描。 该包下面的类,若是有以上四个注解,那么就会将对应的类加入到容器中,id默认为类名首字母转小写。 多个包也能够写,用逗号隔开便可。若是写是一个包下面有多个包, 好比org.example.service,org.example.dao。写到二级包:org.example。Spring会自动扫描全部的子包。 --> <context:component-scan base-package="org.example"/>
因此咱们上面的第三个问题就获得了回答,咱们写Service层须要对应的dao层对应的时候就能够这么写:
@Service public class StudentService { // 伪装Student是dao层,被打上@Autowired的属性,Spring在扫描的时候会自动去容器去寻找对应的类型 // 而后给该属性注入值,因此若是你有两个IOC容器中有两个Student对象,那么可能就会报错 // Spring官方并不推荐如此注入 @Autowired private Student student; public void print(){ System.out.println(student); } }
官方推荐的注入方式是 @Autowired出如今set方法或构造方法上:
@Service public class StudentService { private Student student; @Autowired public StudentService(Student student) { this.student = student; } public void print(){ System.out.println(student); } }
至此咱们上面提出的第一个问题和第三个问题获得了解决:
而后有不懂SpringMVC框架的同窗这里可能就会问了,那我在Servlet中该如何取IOC容器中的对象啊,Servlet的初始化又不像main函数,有个明确的入口,用户是能够从任意一个网页进入的。对于这个问题能够参看:
Spring视频教程的P十一、P十二、P1三、P14。
接着咱们回答第二个问题,难以把握对象的建立时机的这个问题,对于这个问题,Spring框架的答案是条件注解。
IOC容器有两种形式,一种是基于配置文件(咱们上面用的就是),一种是基于注解。条件注解是基于注解形式的,查了一些资料仍是没找到如何用配置文件实现条件注解的。可是基于配置文件的IOC还须要再补充一些,因此下面是先将配置文件形式的讲解完毕后,才会讲基于注解的,条件注解也是基于注解。
咱们知道建立一个对象是有几种不一样的方式的:
一样的在配置文件中配置对象参数的也有几种形式,上面的property的配置的形式就是经过第一种方式来建立对象的。有兴致的同窗能够测试下。
接下来咱们介绍的就是经过第二种方式将对象放入IOC容器中:
<bean id = "studentCard" class = "org.example.StudentCard"> <constructor-arg value="1" index = "0"/> <constructor-arg value="11" index = "1"/> </bean>
constructor-arg有四个属性:
经过反射产生对象:
<bean id = "studentCard" class = "org.example.StudentCard" p:id="1" p:cardNo="23"> </bean>
引用类型经过p:属性名-ref来设定IOC容器中bean的ID
首先咱们准备一个集合的类,构造函数省略,get和set方法省略:
public class CollectionDemo { private List<String> list; private String[] arrayString; private Set<String> set; private Map<String, Object> map; private Properties properties; }
Spring配置文件:
<bean id = "collectionDemo" class = "org.example.CollectionDemo"> <property name="list"> <value> 14 </value> </property> <property name="arrayString"> <array> <value>ddd</value> </array> </property> <property name = "set"> <set> <value>aaa</value> </set> </property> <property name="map"> <map> <entry> <key> <value>zs</value> </key> <value>zs</value> </entry> </map> </property> <property name = "properties"> <props> <prop key="aa">bb</prop> <prop key="cc">dd</prop> </props> </property> </bean>
示例:
public class SpringDemo { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionDemo collectionDemo = (CollectionDemo)applicationContext.getBean("collectionDemo"); System.out.println(collectionDemo); } }
刚学Spring框架的时候,视频上说控制反转,咱们本身再也不new对象,我觉得就是真的再也不new了,就在配置文件里面配就好了,后来随着编码量的上升,才发现这是对Spring框架的一种误解,是有复杂依赖关系的咱们在配置文件里面配,像你要是想用个HashMap,就没必要了。
咱们在配置文件配置对象的时候,用的值都和XML预约义的符号值不冲突,什么意思呢? 假设我给对象的值是<,就会报错。
咱们上面配置Student对象的参数的时候,咱们用的是这种:
<bean id="student" class="org.example.Student"> <property name = "name" value = "zs"></property> <property name = "age" value = "23"></property> <property name = "studentCard" ref = "studentCard"></property> </bean>
咱们称之为value属性注入,其实还能够这么写:
<bean id="student" class="org.example.Student"> <property name = "name" > <value type="java.lang.String">zs</value> </property> <property name = "age" value = "23"></property> <property name = "studentCard" ref = "studentCard"></property> </bean>
咱们称之为value子标签注入。 二者的区别以下:
因此当咱们配置的属性值是< 这个符号的时候咱们就能够这么写:
<bean id="student" class="org.example.Student"> <property name = "name" > <value type="java.lang.String">z<s</value> </property> </bean>
也能够这么写:
<bean id="student" class="org.example.Student"> <property name = "name" > <value type="java.lang.String"><![CDATA[z<3]]></value> </property> </bean>
那我要给属性的值注入null怎么办? 方法有两个
<bean id="student" class="org.example.Student" autowire = "byName"> <property name = "name" > <null/> </property> </bean>
上面咱们提到在Spring的配置文件中配置对象的属性值的时候,若是属性值是对象类型的,那么用ref就能够了,其实这个也能够不写,用自动注入就能够了,用这种自动注入也有两种方式:
<bean id = "studentCard" class = "org.example.StudentCard"> <property name="id" value="1"></property> <property name="cardNo" value="zs"></property> </bean> <bean id="student" class="org.example.Student" autowire = "byName"> <property name = "name" > <value type="java.lang.String"><![CDATA[z<3]]></value> </property> <property name="age"> <value>34</value> </property> </bean>
运行结果再也不展现,假设你把第一个bean标签的id改成studentCard1,那么就注入不了。
<bean id="student" class="org.example.Student" autowire = "byType"> <property name = "name" > <value type="java.lang.String"><![CDATA[z<3]]></value> </property> <property name="age"> <value>34</value> </property> </bean
在xml里面限制仍是挺多的,若是你不当心写错了属性名,那么也是到运行时才能发现错误,若是你不当心给错了类型值,也是到运行时才能发现错误,好比属性是数字类型,你给了一个字符串。不少时候咱们都但愿尽量早的发现错误,那么咱们的配置文件能不能变换一种形式呢? 用代码作配置文件怎么样呢? 好啊,很好的想法啊,那咱们就用代码作配置文件吧。
@Configuration public class SpringConfig { @Bean(name = "studentCard") public StudentCard studentCard(){ return new StudentCard(11,"22"); } @Bean public Student student(@Qualifier("studentCard") StudentCard studentCard){ return new Student(20,"zs",studentCard); } @Bean public StudentCard studentCard2(){ return new StudentCard(11,"22"); } } private static void annotationTest() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); Student student = applicationContext.getBean("student", Student.class); System.out.println(student); }
运行结果:
给一个类打上注解@Configuration
将原先的bean标签变成方法,方法返回对象类型便可。同时方法要加上@Bean注解。方法名默认为id。
能够,在@bean标签中,用name属性自定义就好
像上面同样,在方法参数中写对应的参数便可。
也能够调用对应的方法来完成注入。
你能够本身new,可是为何不直接用IOC容器的呢。
@Qualifier中指定对象名便可。
@import(注解) 、FactoryBean(接口)、ImportBeanDefinitionRegistrar(接口)、ImportSelector(接口)是Spring提供的将对象加入IOC容器的另外方式。
@Configuration @ComponentScan(basePackages = "org.example") // ImportTest是我建的一个空类,用来测试@import,value是一个数组 @Import(value = {ImportTest.class}) public class SpringConfig { }
测试一下:
private static void annotationPrintAllBean() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { System.out.println(beanName); } }
测试结果:
这种方式加进来的bean名是全类名。
首先实现ImportSelector接口:
public class MyImportSelector implements ImportSelector { // 最后返回的即为须要加入到容器的类名 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{ImportTest.class.getName()}; } }
而后在配置类上引入:
@Configuration @ComponentScan(basePackages = "org.example") @Import(value = MyImportSelector.class) public class SpringConfig { }
测试代码:
private static void annotationPrintAllBean() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { System.out.println(beanName); } }
测试结果:
AnnotationMetadata 中携带打上@import注解的配置类上的元信息。
先实现接口:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // BeanDefinitionRegistry能够将bean注册进IOC工厂 // 咱们须要准备一个BeanDefinition。 BeanDefinition beanDefinition = new RootBeanDefinition(ImportTest.class); registry.registerBeanDefinition("importTest",beanDefinition); } }
配置类引入:
@Configuration @ComponentScan(basePackages = "org.example") @Import(value = MyImportBeanDefinitionRegistrar.class) public class SpringConfig { }
测试代码:
private static void annotationPrintAllBean() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { System.out.println(beanName); } }
测试结果:
FactoryBean是一个接口,还有一个接口叫BeanFactory。
反射是框架的灵魂,有的时候,某个bean重复性的属性太多,在配置文件里面配置也是一件让人烦心的事情,可是程序不是擅长作重复工做吗? 咱们可否少写点,从配置文件中读,而后用程序来作这种重复性工做呢?这也就是FactoryBean接口作的事情。
@Component public class MyFactory implements FactoryBean<Car> { private String cardInfo; public MyFactory() { // 伪装从Spring的配置文件中读到了值。 this.cardInfo = "brand,100,200.12";; } /** * 向IOC容器中放入对象 * @return * @throws Exception */ @Override public Car getObject() throws Exception { Car car = new Car(); String[] cardInfoArray = cardInfo.split(","); car.setBrand(cardInfoArray[0]); car.setMaxSpeed(Integer.parseInt(cardInfoArray[1])); car.setPrice(Double.parseDouble(cardInfoArray[2])); return car; } /** * 向IOC容器返回指定的类型 * @return */ @Override public Class<?> getObjectType() { return Car.class; } /** * 设置是不是单例模式 * @return */ @Override public boolean isSingleton() { return false; } }
测试代码:
private static void testFactoryBean() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); // 表明取MyFactory MyFactory myFactory = applicationContext.getBean("&myFactory", MyFactory.class); // 不加&表明取工厂中放入的bean Car car = applicationContext.getBean("myFactory", Car.class); System.out.println(myFactory); System.out.println(car); }
测试结果:
在配置类上加上:
@ComponentScan(basePackages = "org.example", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class})})
是一个枚举类型,值都在FilterType中,一共有六种:
- ANNOTATION 过滤打上指定注解(@Controller,@Component,@Repository,@Service)上的类。
- ASSIGNABLE_TYPE: 指定的类型,已经写在配置类中的,好比说Student类,没法排除。默认应当是先加载配置文件中的类,而后在根据扫描的包,扫描类,去将要加入到IOC容器的对象,加入到IOC容器中。
- ASPECTJ 按照Aspectj的表达式
- REGEX 按照正则表达式
- CUSTOM 自定义规则
我建了一个类,打上了Service注解,如今咱们来测试下:
@Configuration @ComponentScan(basePackages = "org.example", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class})}) // @ComponentScan(basePackages = "org.example", excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {StudentDao.class})}) // @ComponentScan(basePackages = "org.example", includeFilters= {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {StudentDao.class})},useDefaultFilters = false) // @ComponentScan(basePackages = "org.example", includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,value = {MyFilter.class})},useDefaultFilters = false) public class SpringConfig { @Bean(name = "studentCard") public StudentCard studentCard(){ return new StudentCard(11,"22"); } @Bean public Student student(@Qualifier("studentCard") StudentCard studentCard){ return new Student(20,"zs",studentCard); } @Bean public StudentCard studentCard2(){ return new StudentCard(11,"22"); } } private static void annotationTest() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); // 获取IOC容器中全部的bean String[] beanNameArray = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanNameArray) { System.out.println(beanDefinitionName); } }
测试结果:
没有service了。
下面解除第二个@ComponentScan的注释,将第一个@ComponentScan的注释解除掉。再度测试:
会发现StudentDao没了。
与排除指定的类是相似的,只不过Spring默认会加载子包上须要加入到IOC容器中的类,也就是说你想只包含的类在basePackages下面,那么这个包含就是无效的。因此咱们须要经过useDefaultFilters来禁止Spring的默认行为。
咱们注释掉其余的@ComponentScan,只让第三个@ComponentScan解除注释。测试一下:
会发现打上@Service类的对象没了。
自定义规则要实现TypeFilter,像下面这样:
public class MyFilter implements TypeFilter { // 返回true加入到IOC容器中 @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 获取扫描的元数据类型 ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 每扫到子包下的一个类,这个方法就会被调用。 String className = classMetadata.getClassName(); // 只要类名中包含Student的,我就加入到容器中 if (className.contains("Student")){ return true; }else{ return false; } } }
仍是上面的配置类, 咱们解除第四个@ComponentScan的注释,其余的所有注释。测试一下。
HomeStudentCondition是我本身建的类,没加咱们介绍的Spring提供的注解,也加进来了。
条件注解可让某些对象在某些条件知足的状况下,才加入到IOC容器中(等价于建立该对象),若是该条件不知足则该对象不建立,也就是不加入到对应的IOC容器中。那条件该怎么告诉Spring框架呢? 也是经过一个类,这个类要求实现Condition接口。
顺带提一下Spring Boot很大程度上也依赖于条件注解。
首先两个bean:
public class HomeStudent extends Student { /** * 出入证 无参和构造函数 get set方法再也不列出 */ private String pass; } public class BoardStudent extends Student { /** * 宿舍号 无参和构造函数 get set方法再也不列出 */ private String dormitoryNumber; }
而后准备条件,须要实现Condition接口:
public class HomeStudentCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { // 获取当前的环境,通常开发环境分红三套: 开发、测试、生产。 Environment environment = conditionContext.getEnvironment(); // 从环境中获取学生类型 String studentType = environment.getProperty("studentType"); // 若是是住宿学生就加入到IOC容器中 if ("HomeStudent".equals(studentType)){ return true; } return false; } } public class BoardStudentCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String studentType = environment.getProperty("studentType"); if ("BoardStudent".equals(studentType)){ return true; } return false; } }
而后在对应的bean上加上条件变量:
@Configuration @ComponentScan(basePackages = "org.example") public class SpringConfig { @Bean @Conditional(HomeStudentCondition.class) public HomeStudent homeStudent() { return new HomeStudent("出入证"); } @Bean @Conditional(BoardStudentCondition.class) public BoardStudent boardStudent() { return new BoardStudent("宿舍200"); } }
在IDEA中配置环境。
测试代码:
private static void annotationTest() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { System.out.println(beanName); } }
测试结果:
会发现boardStudent没了。
仅在基于WEB的Spring ApplicationContext的状况才生效。
咱们主要经常使用的是singleton和prototype,下面咱们来测试一下:
public class SpringConfig { @Bean(name = "studentCard") public StudentCard studentCard(){ return new StudentCard(11,"22"); } @Bean @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Student student(@Qualifier("studentCard") StudentCard studentCard){ return new Student(20,"zs",studentCard); } @Bean public StudentCard studentCard2(){ return new StudentCard(11,"22"); } } private static void annotationTest() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); Student student1 = (Student) applicationContext.getBean("student"); Student student2 = (Student) applicationContext.getBean("student"); System.out.println(student1 == student2); }
结果:
ConfigurableBeanFactory不是枚举类型,只是有两个常量字符串: singleton和prototype。你直接写这两个字符串中任意一个也行。
配置文件中进行测试:
<bean id="student" class="org.example.Student" scope="prototype"> <property name = "name" > <value type="java.lang.String"><![CDATA[z<3]]></value> </property> <property name="age"> <value>34</value> </property> </bean>
private static void xmlTest() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student1 = (Student) applicationContext.getBean("student"); Student student2 = (Student) applicationContext.getBean("student"); System.out.println(student1 == student2); }
在singleton做用域下,容器在启动的时候就会建立该对象,可是也支持懒加载,即在首次向容器中获取该对象的时候建立。
那么怎么告知IOC容器,在启动的时候,先不要建立呢? 经过@Lazy注解。如何测试呢? 你能够在对应对象的构造函数上,打断点或者输出点东西测试,也能够在启动的时候,打印IOC容器来全部对象的名字来打印。
这里是在对应对象的构造函数上输出一点东西来测试。
@Configuration public class SpringConfig { @Bean(name = "studentCard") public StudentCard studentCard(){ return new StudentCard(11,"22"); } @Bean @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Student student(@Qualifier("studentCard") StudentCard studentCard){ return new Student(20,"zs",studentCard); } @Bean @Lazy public StudentCard studentCard2(){ return new StudentCard(11,"22"); } }
<bean id="student" class="org.example.Student" lazy-init="true"> <property name="age"> <value>34</value> </property> </bean>
这里测试结果就再也不展现了。
上面咱们已经介绍了,自动装配的两个注解了:
@Autowired(required = false),就能够避免在容器中找不到对应类型时抛出错误。
这里咱们再介绍几个:
优先,能够配合@Autowired使用,假设容器里有两个@Autowired须要的对象,在装配时,被打上@Primary的对象,优先被选中
从刚开始的Spring framework,到如今Spring家族已经有不少产品了:
后面咱们将会介绍SpringMVC,接管MVC的C的一个框架。Java领域的问题,在Spring帝国,几乎均可以找到解决方案(一个是方案整合(Spring Cloud),一个是本身提供(Spring MVC)。)
最开始我是从视频开始学习Spring框架的,看视频也是最快学框架的方式,其实看视频的时候,内心仍是有些疑问的,可是又找不到人去问。感受视频中讲的有的时候很牵强,不成系统,零零碎碎的。我不是很喜欢零零碎碎的知识点,我喜欢系统一点的,因而就又系统的整理了一下本身对Spring的理解,也算是入门教程,也算是总结。但愿对各位学习Spring有所帮助。