• 【Java入地】Spring 的 作用域 & MVC & SSM


    Spring Framework 5 框架系列




    概念


    • 什么是Spring?

      • Spring 是一个轻量级的(对象)控制翻转(IOC/DI)和面向切面编程(AOP)的对象容器框架;
      • 极大简化开发过程,降低开发难度;
    • 什么是控制翻转(IOC)?

      Spring 用户相当于窃取 Spring 成果的存在

      举例:

      我 想要生一个孩子

      我 需要付出的代价是:生孩子、喂奶、教他读书……

      我 生孩子的目的是:玩儿、洗完、赚钱、养老……

      现在有一个第三方机构,可以帮我完成生孩子所付出的代价,也就是可以替我生产、喂奶、教学

      所以我只要等着玩孩子、让他洗碗、赚钱就可以了

    • 什么是 依赖注入(DI) ?

      • 对象 new 出来之后,由 Spring 来决定 setget
      • IOC是思想,DI是解决方案
    • 下载

      • 官网(文档最底部)下载最新版的dist压缩包



    五个核心 jar 包


    commons-logging-1.2.jar
    spring-beans-5.1.7.RELEASE.jar
    spring-context-5.1.7.RELEASE.jar
    spring-core-5.1.7.RELEASE.jar
    spring-expression-5.1.7.RELEASE.jar
    

    commons-lang.3.3.9.jar 需要自己下载



    控制翻转 IOC 依赖注入 DI


    • 引用核心类
    public class TestGetBean{
        public static void main(String[] args){
            // 原始方法 创建对象
            Person p = new Person();
            p.setAge(18);
            
            // 控制翻转后 创建对象
            ClsssPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
            // ↑ ↑  通过 ClassPath 查找 xml 文件 applicationContext.xml
            // ↑ ↑  通过 ApplicationContext(应用程序上下文) 查找 应用程序上下文
            // 有了上面两个就可以通过 ctx 进行 getBean 了
            Object bean = (Person)ctx.getBean("person");
            bean.setAge(18);
            bean.setName("张三");
            // -------- 分割线 ---------
            Sout(bean.getName());
            Sout(bean.getAge() );
        }
    }
    
    • 配置文件 applicationContext.xml 中
    // 添加
    <beans …… >
    	<bean id="person" class="com.…….Person"></bean>
    </beans>
    

    解耦合 && 属性


    @Data // Lombok 注释:替代set / get / toString 方法
    public class Person{
    	private Food foot;
    }
    
    @Data
    public class Food{
        private int hungry;
    }
    
    <beans …… >
        <bean id="person" class="…….Person">
        	<constructor-arg name="name" value="zhangsan"></constructor-arg>
          	<constructor-arg name="age" value="18"></constructor-arg>
            <constructor-arg name="food" ref="food"></constructor-arg>
        
        </bean>
    </beans>
    

    <constructor-arg name="name" value="zhangsan"></constructor-arg>

    其中:constructor-arg是属性,value是,ref代表引用其他的类

    Food food = ctx.getBean("food",Food.class);
    
    String a = ToStringBuilder.reflectionToString(person);
    Sout(a);
    

    ApplicationContext.xml 文件的详情


    <project xmlns="http://maven.apache.org/POM/4.0.0" <!--这里只是一个标签-->
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    

    xml文件的定义


    • 加载多个配置文件
    // 文件一: ApplicationContext.xml
    // 文件二: ApplicationContext-service.xml
    // 调用:
    
    // 方法一:
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("ApplicationContext.xml","ApplicationContext-service.xml");
    // 方法二:
    //将字符串定义成一个数组
    
    // 方法三:在一个 XML 文件中使用
    <import resource="applicationContext-service1.xml">
    <import resource="applicationContext-service2.xml">
    // 优化
    <import resource="application-*.xml">
        
    
    // ………………
    

    总结


    • new 换成 <bean id="xxx" class="xxx.class"></bean>
    • set换成 <constructor-arg name="xxx" value="xxx"></constructor-arg>
    • 配置文件的开头部分的功能
    • 引用 一个 / 多个 配置文件的方式



    使用 Spring


    • 引用核心类
    public class TestGetBean{
        public static void main(String[] args){
            ClsssPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
            // ↑ ↑  通过 ClassPath 查找 xml 文件 applicationContext.xml
            // ↑ ↑  通过 ApplicationContext(应用程序上下文) 查找 应用程序上下文
            // 有了上面两个就可以通过 ctx 进行 getBean 了
            Object bean = (Person)ctx.getBean("person");
            bean.setAge(18);
            bean.setName("张三");
            // -------- 分割线 ---------
            Sout(bean.getName());
            Sout(bean.getAge() );
        }
    }
    
    • 配置文件 applicationContext.xml 中
    // 添加
    <beans …… >
    	<bean id="person" class="com.…….Person"></bean>
    </beans>
    





    补充学习



    什么是 单例?




    什么是 Bean?


    bean ,作为一个英文单词的意思是豆子,在 Spring 框架中,Bean 的意思就是一个实体,好比我创建一个 Son.java 如下:

    @Data
    public class Son{
    	private int age;
    	private String name;
    }
    

    那么这个类就是一个 Bean 对象,你创建的所有实体,每一个实体都是一个 Bean;



    MVC 简介( 什么是MVC?)


    • 缘起:
      • 最初没有 MVC 的时候,只是一个简单的基于请求 / 响应的流模式
      • Serviet(request / response) 【请求】 → Service【处理业务逻辑】 → jsp【展示】
      • 【Model 控制层】一个业务逻辑都有一个 具体的类 来处理,将所有的 整合起来,称作 Service
      • 【View 视图层】展示 结果 的一个层,jsp、下载 等
      • 【Controller 接收层】接收前端给的数据层,接收之后给 Model 层来处理



    SSM 结构

    Spring / SpringMVC / Mybatis


    • Spring 作用:new 对象
      • DI 依赖注入(Controller 需要 Service,每次new一个十分消耗性能,DI 可以优化性能);
        • service(单例) - 处理逻辑
        • DAO(单例) - 处理数据库
        • pojo(多例) - 不归Spring容器管理
    • SpringMVC :
      • 一个MVC框架
    • MyBatis:
      • (使用 xml 文件)操作数据库



    为什么用单例?


    • 性能好(节省内存);
    • 迸发情况下,容易产生 线程安全 问题;
    • 容器(如:Spring)接到请求,每一个请求都是一个 线程



    单例类的注意事项:


    • 不能有状态数据,如果有要非常小心;
    • 一个线程改了,另一个线程读了这个样子;
    • ThreadLocal 用来做线程隔离的,线程 与 线程之间不共享,但是 某些实体类或者某些方法中写了private的属性(可以使用set来修改),一个刚set完(或者还没set结束),另一个就也来set了;



    Spring 的作用域

    这三个 Person完全一模一样,存储地址也一样;


    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

    Person person1 = ctx.getBean("person",Person.class);

    Person person2 = ctx.getBean("person",Person.class);

    Person person3 = ctx.getBean("person",Person.class);




    6 种(单例)作用域


    • singleton scope 单例作用域

    • prototype scope 原型作用域

    • websocket scope 基于连接 连接断开的时候对象就消失

    • request 基于请求的,请求打过来,对象就出来(只出来一次)

    • session 基于登录的,对象登陆了,就 new 一个对象(只有一个)

    • application 基于应用程序,应用程序启动,就 new 一个对象




    ApplicationContext.xml 文件中加入 作用域的方式

    做了以上更改之后,new出来的三个对象地址不一样了;


    <bean id="person" scope="prototype" class="com.…….Person">
    	<property name="name" value="和树不困"></property>
    </bean>
    



    Spring 对象生产的两种方式(只有两种)


    • 单例:singleton (每次去的都是同一个),包括
      • websocket
      • request
      • session
      • application
      • 以上四种绑定了生命周期,在一个生命周期内不会有两个不同的对象,getBean 的时候永远都是同一个对象;
    • new 出来: (scope = "prototype")

    当 scope = "prototype" 的时候,每次 getBean 都是新的 Bean,否则都是一个 Bean;



    工厂模式

    创建一个工厂接口,需要什么直接传参生成;


    public interface Car{
        public String getName();
        public String getPrice();
    }
    
    public class AoDi implements Car{
        public String getName(){
            return "奥迪A7";
        }
        
        public String getPrice(){
            return "100w";
        }
    }
    public class BaoMa implements Car{
        public String getName(){
            return "宝马R7";
        }
        
        public String getPrice(){
            return "120w";
        }
    }
    
    
    // 工厂方法
    public class CarFactory{
        public Car getCar(String name){
            if(name.equals("Aodi")){
                retrun new Aodi();
            }else if{
                retrun new BaoMa();
            }else{
                throw new Exception("无法生产这辆车");
            }
        }
    }
    
    public static void main(String[] args){
        Car car = new CarFac
    }
    

    • 在 ApplicationContext.xml 中定义这个工厂
    <bean id="carFactory" class="com.…….carFactory"></bean>
    <bean id="car" factory-bean="carFactory">
        <!--需要 set 方法-->
    	<property name="name" value="Aodi"></property>
    </bean>
    
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    Car car = ctx.getBean("car",Car.class);
    



    循环引用(强引用)

    A引用B / B引用C / C引用A: JVM计数器,当检测到还在被引用的时候就不会销毁它,所以这三个永远都不会被销毁,容易造成内存溢出


    • 在 Spring 中可以检测这种错误的做法,并作出提醒
    • 单例模式是可以允许这样引用的,但是 new 或者 prototype 是不允许的
    • 同时有 单例模式 & prototype 模式是允许的, 并且单例对象的引用对象也变成了单例的。



    Spring 初始化 Bean 的四种方式(初始化顺序)


    • 按照 Bean 标签的顺序
    // ApplicationContext.cml
    <bean id="a" class="………….A.class"></bean>
    

    <bean>标签的位置越靠前,则初始化越早;


    • 先加载 depends-on=" " 依赖于:
    // ApplicationContext.cml
    <bean id="a" class="………….A.class" depends-on="B"></bean>
    

    A depends-on B,则在初始化 A 之前一定会初始化 B;


    • 懒加载

    <lazy-init="true">,用到哪个加载哪个,不用到不加载。


    <bean id="a" class="…….class" lazy-init="true" > 
    
    </bean>
    

    • 强 / 弱引用

    强引用:A完全持有一个类B,如果A不初始化,则这个类完全不能运行;
    弱引用:A在一个方法里面用到了B的某一个属性值,不初始化B顶多A 的方法会报废;


    <bean id="a" class="…….class" lazy-init="true">
    	<property name="name">
        <value></value>
        </property>
    </bean>
    
    <bean id="b" class="…….class" lazy-init="true">
        <property name="name">
    		<null></null>
        </property>
    </bean>
    
    <bean id="b" class="…….class" lazy-init="true">
    </bean>
    
    // 运行结果(TtoStringBuilder):
    
    b.getName = null // 空指针
    a.getName = 	 // 空字符串
    
    a.getName().equals("");// true
    b.getName().equals("");// 报错
    



    自动装配

    byName 匹配 ID ,A 里面引用的是 b 所以 B 的 id="b"可以,但是byType引用的是 C 这个类型;


    <bean id="A" class="…….A" autowire="byName"></bean>
    <bean id="b" class="…….B" autowire="byType"></bean>
    <bean id="C" class="…….C" autowire="byName"></bean>
    
    • 配置默认装配的类型
    <beans ……………… default-autowire="byType">
    	<bean> …… </bean>
        <bean> …… </bean>
        <bean> …… </bean>
    </beans>
    



    学习要求


    • 掌握作用域
    • 掌握单例
    • 理解 MVC 与 SSM
    • 掌握工厂方式





    总结:





    Spring 的执行流程


    在这里插入图片描述

    我们从前端访问Controller层,又从Controller层访问数据库,就可以到达一个简单的 Spring 框架,但是这样执行的话 Controller 层既要接收前端数据 又要 处理数据 还要对接数据库,所以将“处理数据”这一部分单独划分出去,作为 Service 层,将 “ 对接数据库 ” 这一部分 分离出去,所谓,Mapper层,也就是常说的 Dao 层。

    由于前端给出的访问不可能一次只有一个,所以我们实例化的对象不能是单例的,否则ABCD同时登陆的话,登录的可能是同一个用户。


    为了让代码看起来更简洁,所以可以在 Application.xml 中写入 Bean 对象,直接实例化便可以 创建 / 引用 一个对象;


    由于我们在编程的时候广泛使用注解,所以我们将逐个注解细分,常用注解如下:


    注解名称 用途 备注
    @Controller Controller层 用于标注当前是Controller层
    @Service Service层 用于标注当前是Service层
    @Mapper Mapper层 用于标注当前是Mapper层
    @autowire 任意层 用于自动装配,下方举例子
    @value 测试时给初值
    @Data get / set / toString 方法的汇总 在实体类的最上方写上这个方法则不用再写set / get 方法,当然你可以对方法进行重写
    @Override 方法重写的时候标注在上面,可以自动检错;
    • autowire 说明
    //在Mapper层创建一个 SonService.java 的接口,用于连接数据库读取 Son 这个实体
    public class SonController{ // Son 的 Controller 层
    	@autowire Sonservice sonService // 这样就创建了一个 SonService 的接口
    	List<son> sonList = sonService.list(); //这样就能获取 son 数据库中所有的数据
    }
    
  • 相关阅读:
    5 个非常实用的 vs 调试技巧
    神秘的 _DEBUG 宏从何处来?
    调试实战 —— dll 加载失败之 Debug Release 争锋篇
    Python 基础 —— 字符串 方法
    linux shell的一些技巧
    salt 一些state模块函数的使用方法记录
    salt 添加iptables的sls例子
    linux 内置函数 操作
    zabbix 自动发现 自动添加主机
    zabbix 触发器 的表达式函数
  • 原文地址:https://www.cnblogs.com/hskcool/p/14271914.html
Copyright © 2020-2023  润新知