工作及面试的过程中,作为Java开发,Spring环绕在我们的身边,很多人都是一知半解,本次将用14天时间,针对容器中注解、组件、源码进行解读,AOP概念进行全方面360°无死角介绍,SpringMVC知识介绍与讲解,将整个Spring进行一个整体介绍,学会承包你后面所有的装逼,吊打面试官。你学“废”了嘛~

一、Spring基础

Spring是什么

Spring是一种开源轻量级框架,是为了解决企业应用程序开发复杂性而创建的。Spring致力于解决JavaEE的各层解决方案,而不仅仅于某一层方案。

Spring发展历程

2003年2月Spring框架正式成为一道开源项目,Spring致力于J2EE应用的各种解决方案,而不仅仅专注于某一层解决方案。可以说Spring是企业应用开发的“一站式”选择,Spring贯穿于表现层、业务层、持久层,然而Spring并不想取代那些已经有的框架,而是以高度的开放性,与这些已有的框架进行整合。

Spring的目标

  1. 让现有的技术更容易使用

  2. 促进良好的编程习惯

Spring是一个全面的解决方案,它坚持一个原则:从不重新造轮子。

已经有较好解决方案的领域,Spring绝不重复实现。比如:对象持久化和OR映射;

Spring只对现有的JDBC、Hibernate等技术提供支持,使之更容易使用,而不做重复实现。Spring框架有很多特性,这些特性由7个定义良好的模块构成。

Spring体系结构

SpringCore ApplicationContext SpringWeb MVC SpringDAO ORM AOP

1. Spring Core:Spring核心,它是框架最基础的部分,提供IOC和依赖注入的特性;

2. Spring Context:Spring上下文容器,它是BeanFactory功能加强的一个子接口;

3. Spring Web:它提供Web应用开发的支持;

4. Spring MVC:它针对Web应用中MVC思想的实现;

5. Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性;

6. Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis的整合等等;

7. Spring AOP:AOP,即面向切面编程,它提供了与AOP联盟兼容的编程实现。

(关于IOC、AOP等概念,后续会偷偷讲解)

Spring常用组件

接下来就将对各组件及注解进行详细分析

一、将工程从XML到注解

作为Javaer,都知道最开始时候,都是在xml文件里面去注入bean对象:

bean.xml

  1.  
    <?xml version="1.0" encoding="UTF-8"?>
  2.  
    <beans xmlns="http://www.springframework.org/schema/beans"
  3.  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6.  
    <bean id="person" class="com.cansluck.spring1.Person">
  7.  
    <property name="name" value="Cansluck"></property>
  8.  
    <property name="age" value="29"></property>
  9.  
    </bean>
  10.  
    </beans>

类似上面的bean对象,在xml文件里面将其注入并定义属性,这样非常的麻烦。

我们如果调用的话需要用到ClassPathXmlApplicationContext类,用来获取类路径下的xml。

创建一个person实体类:

  1.  
    public class Person {
  2.  
    private String name;
  3.  
    private Integer age;
  4.  
  5.  
    public Person(){
  6.  
    super();
  7.  
    }
  8.  
    public String getName() {
  9.  
    return name;
  10.  
    }
  11.  
    public void setName(String name) {
  12.  
    this.name = name;
  13.  
    }
  14.  
    public Person(String name, Integer age) {
  15.  
    super();
  16.  
    this.name = name;
  17.  
    this.age = age;
  18.  
    }
  19.  
    public Integer getAge() {
  20.  
    return age;
  21.  
    }
  22.  
    @Override
  23.  
    public String toString() {
  24.  
    return "Person [name=" + name + ", age=" + age + "]";
  25.  
    }
  26.  
    public void setAge(Integer age) {
  27.  
    this.age = age;
  28.  
    }
  29.  
    }

再定义一个测试类:

  1.  
    import org.springframework.context.ApplicationContext;
  2.  
    import org.springframework.context.support.ClassPathXmlApplicationContext;
  3.  
  4.  
    public class MainTest1 {
  5.  
    public static void main(String[] args) {
  6.  
    // 把beans.xml的类加载到容器
  7.  
    ApplicationContext app
  8.  
    = new ClassPathXmlApplicationContext("bean.xml");
  9.  
    // 从容器中获取bean
  10.  
        Person person = (Person) app.getBean("person");
  11.  
    System.out.println(person);
  12.  
    }
  13.  
    }

作为开发者,是不能忍受这样一个一个重复去造轮子去写的,如果用注解开发,很明显是不需要xml的。因此Spring提供了@Configuration注解,关于Configuration注解使用,官方文档描述:

1. @Configuration注释类表明其主要目的是作为bean定义的源

2. @Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系

作者认为,@Configuration就等于配置文件,配置文件如下:

  1.  
    package com.cansluck.spring1.config;
  2.  
  3.  
    import org.springframework.context.annotation.Bean;
  4.  
    import org.springframework.context.annotation.Configuration;
  5.  
  6.  
    import com.enjoy.cap1.Person;
  7.  
  8.  
    // 配置类====配置文件
  9.  
    @Configuration
  10.  
    public class MainConfig {
  11.  
  12.  
    // 给容器中注册一个bean, 类型为返回值的类型
  13.  
    @Bean
  14.  
    public Person person01(){
  15.  
    return new Person("Cansluck", 20);
  16.  
    }
  17.  
    }

通过定义一个配置类MainConfig,加上@Configuration注解,就不需要再在xml文件里面写更多的bean对象实例。

通过使用:

@AnnoatationConfigApplicationContext注解,来获取IOC容器。

使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。

避免使用application.xml进行配置。相比XML配置,更加便捷。

通过测试类可以发现,并不需要再定义xml文件,通过加载类就能直接获取到bean对象。

  1.  
    import org.springframework.context.ApplicationContext;
  2.  
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  3.  
    import org.springframework.context.support.ClassPathXmlApplicationContext;
  4.  
  5.  
    import com.enjoy.cap1.config.MainConfig;
  6.  
  7.  
    public class MainTest2 {
  8.  
    public static void main(String[] args) {
  9.  
    // 把beans.xml的类加载到容器
  10.  
    // ApplicationContext app
  11.  
        //    = new ClassPathXmlApplicationContext("beans.xml");
  12.  
  13.  
    ApplicationContext app
  14.  
    = new AnnotationConfigApplicationContext(MainConfig.class);
  15.  
  16.  
    // 从容器中获取bean
  17.  
        // Person person = (Person) app.getBean("person01");
  18.  
    // System.out.println(person);
  19.  
  20.  
    String[] namesForBean = app.getBeanNamesForType(Person.class);
  21.  
    for (String name : namesForBean) {
  22.  
    System.out.println(name);
  23.  
    }
  24.  
    }
  25.  
    }

二、ComponentScan扫描规则

ComponentScan:定义扫描规则,制定扫描哪些组件

首先我们来看一下ComponentScan接口,我们主要关注以下几个参数:

value:指定要扫描的包

useDefaultFilters:默认为true,表示扫描所有组件,如果要自定义扫描范围,则必须将其改为false

includeFilters:Filter[] 指定扫描的时候,只需要包含哪些组件

excludeFilters:Filter[] 指定扫描的时候,按照什么规则,排除哪些组件

扫描规则有:

FilterType.ANNOTATION:按照注解扫描

FilterType.ASSIGNABLE_TYPE:按照给定的类型比如按照PersonService类型

FilterType.ASPECTJ:使用ASPECTJ表达式

FilterType.REGEX:使用正则表达式

FilterType.CUSTOM:使用自定义规则,自己写一个类,实现TypeFilter接口

看实现:

1.使用@ComponentScan(value="com.cansluck.spring1")表示扫描此目录下的所有包。

配置类:

  1.  
    import org.springframework.context.annotation.Bean;
  2.  
    import org.springframework.context.annotation.ComponentScan;
  3.  
    import org.springframework.context.annotation.ComponentScan.Filter;
  4.  
    import org.springframework.context.annotation.Configuration;
  5.  
    import org.springframework.context.annotation.FilterType;
  6.  
  7.  
    import com.enjoy.cap1.Person;
  8.  
  9.  
    @Configuration
  10.  
    @ComponentScan(value="com.cansluck.spring1")
  11.  
    public class MainConfig {
  12.  
    // 给容器中注册一个bean, 类型为返回值的类型,
  13.  
    @Bean
  14.  
    public Person person01() {
  15.  
        return new Person("Cansluck", 20);
  16.  
    }
  17.  
    }

2.定制包扫描时的过滤规则

  1.  
    import org.springframework.context.annotation.Bean;
  2.  
    import org.springframework.context.annotation.ComponentScan;
  3.  
    import org.springframework.context.annotation.ComponentScan.Filter;
  4.  
    import org.springframework.context.annotation.Configuration;
  5.  
    import org.springframework.context.annotation.FilterType;
  6.  
  7.  
    import com.enjoy.cap1.Person;
  8.  
  9.  
    @Configuration
  10.  
    @ComponentScan(value="com.cansluck.spring1", includeFilters = {
  11.  
    @Filter(type=FilterType.CUSTOM, classes={CansluckTypeFilter.class})
  12.  
    }, useDefaultFilters=false)
  13.  
    public class MainConfig {
  14.  
    // 给容器中注册一个bean, 类型为返回值的类型,
  15.  
    @Bean
  16.  
    public Person person01(){
  17.  
    return new Person("Cansluck", 20);
  18.  
    }
  19.  
    }

在配置类MainConfig加入扫描配置@Filter:自定义扫描规则

扫描规则上面有讲过,有:

FilterType.ANNOTATION:按照注解扫描

FilterType.ASSIGNABLE_TYPE:按照给定的类型比如按照PersonService类型

FilterType.ASPECTJ:使用ASPECTJ表达式

FilterType.REGEX:使用正则表达式

FilterType.CUSTOM:使用自定义规则,自己写一个类,实现TypeFilter接口

5中扫描规则,上面为自定义规则,其余的可以自行去实现一下,主要可以实现Annotation(按照注解扫描) 和 ASSIGNABLE_TYPE(按照给定类型)。

自定义一个配置类:CansluckTypeFilter实现TypeFilter接口:

  1.  
    import java.io.IOException;
  2.  
  3.  
    import org.springframework.core.io.Resource;
  4.  
    import org.springframework.core.type.AnnotationMetadata;
  5.  
    import org.springframework.core.type.ClassMetadata;
  6.  
    import org.springframework.core.type.classreading.MetadataReader;
  7.  
    import org.springframework.core.type.classreading.MetadataReaderFactory;
  8.  
    import org.springframework.core.type.filter.TypeFilter;
  9.  
  10.  
    public class CansluckTypeFilter implements TypeFilter{
  11.  
    private ClassMetadata classMetadata;
  12.  
  13.  
    /*
  14.  
    * MetadataReader:读取到当前正在扫描类的信息
  15.  
    * MetadataReaderFactory:可以获取到其他任何类信息
  16.  
    */
  17.  
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
  18.  
    throws IOException {
  19.  
    // 获取当前类注解的信息
  20.  
    AnnotationMetadata annotationMetadata
  21.  
    = metadataReader.getAnnotationMetadata();
  22.  
    // 获取当前正在扫描的类信息
  23.  
    classMetadata = metadataReader.getClassMetadata();
  24.  
    // 获取当前类资源(类的路径)
  25.  
    Resource resource = metadataReader.getResource();
  26.  
  27.  
    String className = classMetadata.getClassName();
  28.  
    System.out.println("----->" + className);
  29.  
    // 当类包含er字符, 则匹配成功,返回true
  30.  
        if(className.contains("er")) {
  31.  
    return true;
  32.  
    }
  33.  
    return false;
  34.  
      }
  35.  
    }

三、Scope扫描规则

方法没有加@Scope注解之前,默认的bean是单例的

prototype:多实例,IOC容器启动并不会去调用方法创建对象在容器中,而是每次获取的时候才会调用方法创建对象,具体看下面实例

singleton:单实例(默认),IOC容器启动会调用方法创建对象到IOC容器中,以后每次获取就是直接从容器(可以理解为从map.get("")对象)中获取

request:主要针对Web应用,同义词请求创建一个实例

session:同一个session创建一个实例

(request、session两个用的不多,了解即可)

配置类:

  1.  
    import org.springframework.context.annotation.Bean;
  2.  
    import org.springframework.context.annotation.ComponentScan;
  3.  
    import org.springframework.context.annotation.ComponentScan.Filter;
  4.  
    import org.springframework.context.annotation.ComponentScans;
  5.  
    import org.springframework.context.annotation.Configuration;
  6.  
    import org.springframework.context.annotation.FilterType;
  7.  
    import org.springframework.context.annotation.Scope;
  8.  
    import org.springframework.stereotype.Controller;
  9.  
  10.  
    import com.enjoy.cap1.Person;
  11.  
    import com.enjoy.cap2.controller.OrderController;
  12.  
  13.  
    @Configuration
  14.  
    public class MainConfig {
  15.  
    // 给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
  16.  
    /*
  17.  
    * prototype:多实例,IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
  18.  
    * singleton:单实例(默认),IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
  19.  
    * request: 主要针对web应用, 递交一次请求创建一个实例
  20.  
    * session:同一个session创建一个实例
  21.  
    */
  22.  
    @Scope("prototype")
  23.  
    @Bean
  24.  
    public Person person() {
  25.  
    return new Person("Cansluck", 20);
  26.  
    }
  27.  
    }

测试类:

  1.  
    public class Test {
  2.  
    @Test
  3.  
    public void test01(){
  4.  
    AnnotationConfigApplicationContext app
  5.  
    = new AnnotationConfigApplicationContext(MainConfig.class);
  6.  
  7.  
    String[] names = app.getBeanDefinitionNames();
  8.  
  9.  
    for(String name : names) {
  10.  
    System.out.println(name);
  11.  
    }
  12.  
    // 从容器中分别取两次person实例, 看是否为同一个bean
  13.  
    Object bean1 = app.getBean("person");
  14.  
    Object bean2 = app.getBean("person");
  15.  
    System.out.println(bean1 == bean2);
  16.  
        // 结论:bean1就是bean2,同一个对象
  17.  
    }
  18.  
    }

结论:

  1. @Scope("singleton"),取的的结果true,证明取到的是同一个person的bean,只实例化了一次

  2. @Scope("prototype"),取的的结果false,证明取到的不是同一个person的bean,说明被多次实例化

四、lazy懒加载

配置类:

  1.  
    import org.springframework.context.annotation.Bean;
  2.  
    import org.springframework.context.annotation.ComponentScan;
  3.  
    import org.springframework.context.annotation.ComponentScan.Filter;
  4.  
    import org.springframework.context.annotation.ComponentScans;
  5.  
    import org.springframework.context.annotation.Configuration;
  6.  
    import org.springframework.context.annotation.FilterType;
  7.  
    import org.springframework.context.annotation.Lazy;
  8.  
    import org.springframework.context.annotation.Scope;
  9.  
    import org.springframework.stereotype.Controller;
  10.  
  11.  
    import com.enjoy.cap1.Person;
  12.  
    import com.enjoy.cap2.controller.OrderController;
  13.  
  14.  
    @Configuration
  15.  
    public class MainConfig {
  16.  
    // 给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
  17.  
    /*
  18.  
    * 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
  19.  
       * 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
  20.  
    */
  21.  
    @Lazy
  22.  
    @Bean
  23.  
    public Person person(){
  24.  
    System.out.println("给容器中添加person.......");
  25.  
    return new Person("Cansluck", 20);
  26.  
    }
  27.  
    }

测试类:

  1.  
    public class Test {
  2.  
    @Test
  3.  
    public void test01(){
  4.  
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
  5.  
  6.  
    System.out.println("IOC容器创建完成........");
  7.  
    // 执行获取的时候才创建并初始化bean
  8.  
    app.getBean("person");
  9.  
    }
  10.  
    }

当配置类中加入@Lazy时,只有获取getBean()时才会加载到容器中。

往后14天会持续更新Spring相关的知识,并且针对注解,源码等结合代码做讲解。

< END >

Java极客思维

微信扫一扫,关注公众号

不要再说不会Spring了!Spring第一天,学会进大厂!的更多相关文章

  1. Spring第一篇【介绍Spring、引入Spring、Spring六大模块】

    前言 前面已经学习了Struts2和Hibernate框架了.接下来学习的是Spring框架-本博文主要是引入Spring框架- Spring介绍 Spring诞生: 创建Spring的目的就是用来替 ...

  2. spring Boot+spring Cloud实现微服务详细教程第一篇

    前些天项目组的大佬跟我聊,说项目组想从之前的架构上剥离出来公用的模块做微服务的开发,恰好去年的5/6月份在上家公司学习了国内开源的dubbo+zookeeper实现的微服务的架构.自己平时对微服务的设 ...

  3. Spring之旅第一篇-初识Spring

    一.概述 只要用框架开发java,一定躲不过spring,Spring是一个轻量级的Java开源框架,存在的目的是用于构建轻量级的J2EE应用.Spring的核心是控制反转(IOC)和面向切面编程(A ...

  4. spring boot实战(第一篇)第一个案例

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   spring boot实战(第一篇)第一个案例 前言 写在前面的话 一直想将spring boot相关内容写成一个系列的 ...

  5. Spring Boot学习第一部分(Spring 4.x)第一章(Spring 基础)

    1.spring概述 1.1.spring的简史 第一阶段:XML配置spring 1.x时代, 第二阶段:注解配置spring 2.x时代, @Controller @Service @Compon ...

  6. Spring in Action 第一章 Spring之旅

    1.1 简化Java开发 1.1.2 依赖注入(DI) 松耦合:如果一个对象只通过接口(而不是具体实现或初始化过程)来表明依赖关系,那么这种依赖就能在对象本身毫不知情的情况下,用不同的具体实现进行替代 ...

  7. Spring MVC -- Spring框架入门(IoC和DI)

    Spring MVC是Spring框架中用于Web应用开发的一个模块.Spring MVC的MVC是Model-View-Controller的缩写.它是一个广泛应用于图像化用户交互开发中的设计模式, ...

  8. velocity+spring mvc+spring ioc+ibatis初试感觉(与struts+spring+hibernate比较)

    velocity+spring mvc+spring ioc+ibatis框架是我现在公司要求采用的,原因是因为阿里巴巴和淘宝在使用这样的框架,而我公司现在还主要是以向阿里巴巴和淘宝输送外派人员为 主 ...

  9. SSM(spring mvc+spring+mybatis)学习路径——1-2、spring事务管理

    目录 1-2 Spring事务管理 概念介绍 事务回顾 事务的API介绍 Spring 事务管理 转账案例 编程式事务管理 声明式事务管理 使用XML配置声明式事务 基于tx/aop 使用注解配置声明 ...

随机推荐

  1. docker查看ip

    docker查看容器的网络ip   docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' conta ...

  2. kibana-安装-通过docker

      拉取镜像 docker pull kibana:7.9.1   创建用户自定义网络 docker network create esnet   运行Kibana docker run --name ...

  3. spring boot:接口站增加api版本号后的安全增强(spring boot 2.3.3)

    一,接口站增加api版本号后需要做安全保障? 1,如果有接口需要登录后才能访问的, 需要用spring security增加授权 2,接口站需要增加api版本号的检验,必须是系统中定义的版本号才能访问 ...

  4. ansible使用playbook的简单例子(ansible2.9.7)

    一,ansible使用playbook的优点 1,用ansible执行一些简单的任务,使用ad-hoc命令就可以解决问题 如果执行复杂的功能,需要大量的操作,执行的ad-hoc命令会不够方便,这时我们 ...

  5. centos8平台使用ethtool配置网卡

    一,ethtool命令所属的包 [root@centos8 liuhongdi]# whereis ethtool ethtool: /usr/sbin/ethtool /usr/share/man/ ...

  6. Tomcat6.0 支持 https

    环境信息 Linux系统 + Tomcat  (程序页面可以运行前提下) 条件:安装了JDK 查看指定版本信息 1 进入$JAVA_HOME/bin目录     (一般是这个目录  /usr/java ...

  7. CentOS 8 Yum安装ansible

    ansible的安装 直接yum安装ansible会报错,需要先安装epel源. ansible的安装来源于epel仓库,因此在安装前需确保安装了正确的epel源. yum install -y ep ...

  8. CDH+Kylin三部曲之二:部署和设置

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. servlet post response.sendRedirect 乱码

    response.sendRedircet一般用于传递字符串参数 常会出现乱码: 情景1: post表单提交,跳转后的servlet,通过getParameter(name)进行解码,获取的中文乱码 ...

  10. 拿了十几个offer,怎样做选择?

    本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 最近收到好几个读者的咨询,关于如何选offer的 ...