简介
Spring框架是一个容器,是整合其他框架的框架
他的核心是IOC(控制反转)和AOP(面向切面编程),由20多个模块构成,在很多领域都提供了优秀的问题解决方案
特点
轻量级:由20多个模块构成,每个jar包都很小,小于1M,核心包也就3M左右
代码污染小:Spring框架对程序员开发时的条条框框的约束较少,对代码的污染小
面向接口编程:灵活性好,项目的可扩展性和可维护性都较高
整合其他框架:使其他框架也更加易用
AOP:面向切面编程,将公共的,通用的,重复的代码单独开发,在需要时反织回去
示例:
示例分析:在开发中普遍需要使用到日志输出功能,会将日志输出功能大量耦合到项目的不同位置,如上图左侧所示。
而日志输出功能与项目本身的核心业务逻辑无关,我们只是为了不时的查看程序的运行状态。则可以将日志功能单独提出去开发,在需要的地方将日志输出功能(所谓:切面)反织回去即可,如上图右侧所示。
IOC
IOC(Inversion of Control):是一个概念,也是一种思想,由Spring容器进行对象的创建和依赖注入,程序员在使用时直接取用即可
正转示例
//程序员创建对象Student stu =newStudent();//程序员进行赋值stu.setName("荷包蛋");stu.setAge(20);
反转示例
<!-- Spring容器负责对象的创建 --><!-- Spring容器负责为属性赋值 -->
创建Spring项目
创建maven的java项目:模板类型 + 项目目录结构 + 修改pom.xml文件添加基本配置的操作不再赘述,可以参考mybatis博客集里对maven项目的配置
在pom.xml里添加Spring依赖
<!-- 添加spring依赖-->org.springframeworkspring-context5.3.22
在src/main/resources目录下添加Spring配置文件:applicationContext.xml(idea在下图状态下,无法截图,手机拍摄,包涵包涵)
正常情况下,文件头自动补全
创建实例对象:容器与手工创建对比
实体类
packagecom.example.pojo;publicclassStudent{privateString name;privateintage;publicStudent(){ System.out.println("无参方法被调用,Student实例被创建....."); }@OverridepublicStringtoString(){return"Student{"+"name='"+ name +'\''+", age="+ age +'}'; }}
applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?><!-- 定义实体类的实例对象 -->
两种创建实例对象的对比
packagecom.example.test;importcom.example.pojo.Student;importorg.junit.Test;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassTestStudent{//测试程序员手动创建实例对象@TestpublicvoidtestStudent(){ Student stu =newStudent(); System.out.println(stu); }//测试Spring容器创建实例对象@TestpublicvoidtestStudentSpring(){//创建Spring容器,并启动ApplicationContext applicationContext =newClassPathXmlApplicationContext("applicationContext.xml");//从容器中获取对象Student stu = (Student) applicationContext.getBean("stu"); System.out.println(stu); }}
两次测试的输出结果均为
无参方法被调用,Student实例被创建..... Student{name='null', age=0} Process finished withexitcode 0
当Spring容器创建时,对应的应用域中注册的对象就会被创建
@TestpublicvoidtestStudentSpring(){//创建Spring容器ApplicationContext applicationContext =newClassPathXmlApplicationContext("source01/applicationContext.xml"); }
测试输出结果
无参方法被调用,Student实例被创建..... Process finishedwithexitcode0
基于xml的setter注入
1.简单类型(8 + 1)注入:使用value属性
添加两个属性的set方法
publicvoidsetName(String name){this.name = name; }publicvoidsetAge(intage){this.age = age; }
使用setter注入法为实例对象的属性赋值
测试Spring容器创建实例对象
@TestpublicvoidtestStudentSpring(){//创建Spring容器,并启动ApplicationContext applicationContext =newClassPathXmlApplicationContext("source01/applicationContext.xml");//从容器中获取对象Student stu = (Student) applicationContext.getBean("stu"); System.out.println(stu); }
测试输出
无参方法被调用,Student实例被创建..... Student{name='荷包蛋', age=20} Process finished withexitcode 0
2.引用类型注入:使用ref属性
新增School类
privateStringname;privateStringaddress;publicvoidsetName(Stringname) {this.name = name; }publicvoidsetAddress(Stringaddress) {this.address = address; }publicSchool() { System.out.println("School类的构造方法被执行,实体对象被创建....."); }@OverridepublicStringtoString() {return"School{"+"name='"+ name +'\''+", address='"+ address +'\''+'}'; }
Student对象持有School对象的引用
privateString name;privateintage;privateSchool school;publicStudent(){ System.out.println("Student类的构造方法执行,实体对象被创建...."); }publicvoidsetName(String name){this.name = name; }publicvoidsetAge(intage){this.age = age; }publicvoidsetSchool(School school){this.school = school; } @OverridepublicStringtoString(){return"Student{"+"name='"+ name +'\''+", age="+ age +", school="+ school +'}'; }
applicationContext.xml文件
<!-- 定义School实体类的实例对象--><!-- 定义Student实体类的实例对象 --><!-- 根据bean工厂中注册过的对象,进行依赖注入 --><!--
对于Student对象持有的School对象的引用
根据bean工厂中注册过的对象(不分注册先后),进行依赖注入
(待注入属性类型必须和已经注册过的对象的类型一致,才可进行依赖注入)
-->
测试setter注入法的ref属性
@TestpublicvoidtestStudent(){//创建Spring容器,同时生成bean工厂中注册的对象ApplicationContext applicationContext =newClassPathXmlApplicationContext("source02/applicationContext.xml");//获取对象Student stu = (Student) applicationContext.getBean("stu"); System.out.println(stu); }
测试输出结果
School类的构造方法被执行,实体对象被创建..... Student类的构造方法执行,实体对象被创建.... Student{name='荷包蛋', age=20, school=School{name='nefu', address='哈尔滨'}} Process finished withexitcode 0
注意
使用setter注入法必须提供无参构造方法,必须提供待注入属性的setXXX()方法,简单分析如下:无参构造方法用于创建实例对象,此时实例对象的属性是一张白纸,未被赋值和被其他数据污染对应属性的set方法是为了在底层调用时给目标属性赋值用,框架再封装,底层的执行代码该有的还要有,框架也不知道你在set方法中都想干些什么(毕竟set方法应该被用来赋值,但是不仅仅只能做赋值用)有了前两步,你便可以得到需要的对象,而且只有指定的属性被赋值,其他属性一尘不染但是,如果提供了有参构造方法,或者没有set方法,setter注入将会遇到无限多的麻烦无set方法,底层无法调用对应set方法完成属性赋值有参构造方法的参数会扰乱我们对指定属性的赋值计划例如,有参构造包括name和age两个属性,而set又要对name属性注入值,就会导致name属性被两次赋值,在创建对象时就这样做显然不合理所以,我们要做的就是,先创建一个干净的对象(无参构造,先不涉及属性值的问题),再用对应属性的set方法给属性赋值,做到精准赋值,按需操作
网友评论