Spring
spring是什么
Spring是一个主流的JavaWeb开发框架,该框架是一个轻量级的应用框架,具有很高的凝聚力和吸引力。Spring框架因为其强大的功能和牛逼的性能越来越受开发人员的喜欢。那就跟光棍五十年遇到女人一样的饥渴啊。
Spring是分层的 Java SE/EE full-stack 轻量级开源框架,以IOC(Inverse of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为内核,使用基本的JavaBean完成以前只可能由EJB完成的工作,取代了EJB臃肿和低效的开发模式。
在实际开发中,通常服务器端采用分层架构——表现层(web)、业务逻辑层(service)、持久层(dao)。
Spring对每一层都提供了技术支持,在表现层提供了与Struts2框架的整合,在业务逻辑层可以管理事务和记录日志,在持久层可以整合Hibernate和JdbcTemplate等技术。
从设计上看,Spring框架给予了Java程序员更高的自由度(像苏菲一样,想咋跳就咋跳),所以受到了业界的一致好评。
Spring具有简单,可测试和松耦合等特点,不仅可以用于服务器端的开发,也可以应用于任何Java应用的开发中。
Spring特点是什么
支持AOP,方便进行面向切面的编程
方便解耦:简化开发,通过Spring提供的IoC容器(控制反转),利用依赖关系注入的方式,实现对象之间的解耦。
支持声明式事务处理,只需要通过配置就可以完成对事物的管理,而无须手动编程
方便程序的测试:Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持。
降低Java EE API的使用难度:Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
非侵入式设计 Spring是一种非侵入式(non-invasive)框架,它可以使应用程序代码对框架的依赖最小化。
Spring优势什么
1)方便解耦,简化开发
Spring就像一个大工厂,可以将所有对象的创建和依赖关系的维护交给Spring管理(你可以想象一下养老院)
2)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts2、Hibernate、MyBatis)的直接支持。
3)降低Java EE API 的使用难度
Spring对Java EE 开发中非常难用的一些API(JDBC、JavaMail、远程调用等)都提供了封装,使这些API应用的难度大大降低。
4)方便程序的测试
Spring支持JUnit4,可以直接通过注解方便的测试Spring程序
5)AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截和运行监控等功能。
6)声明事务的支持
只需要通过配置就可以完成对事务的管理,而不用我们去手动编程。
耦合是什么意思
耦合是指两个实体相互依赖于对方的一个量度。
分为以下几种:
- 非直接耦合:两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的
- 数据耦合:一个模块访问另一个模块时,彼此之间是通过简单数据参数 (不是控制参数、公共数据结构或外部变量) 来交换输入、输出信息的。
- 标记耦合 :一组模块通过参数表传递记录信息,就是标记耦合。这个记录是某一数据结构的子结构,而不是简单变量。
- 控制耦合:如果一个模块通过传送开关、标志、名字等控制信息,明显地控制选择另一模块的功能,就是控制耦合。
- 外部耦合:一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
- 公共耦合:若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。
- 内容耦合:如果发生下列情形,两个模块之间就发生了内容耦合
- (1) 一个模块直接访问另一个模块的内部数据;
- (2) 一个模块不通过正常入口转到另一模块内部;
- (3) 两个模块有一部分程序代码重迭(只可能出现在汇编语言中);
- (4) 一个模块有多个入口。
spring核心是什么
1.控制反转(IoC,Inversion of Control)
传统的JAVA开发模式中,当需要一个对象时,我们使用new或者通过getInstance等直接或者间接调用构造方法创建一个对象,而在Spring开发模式中,Spring容器使用工厂模式为我们创建了所需要的对象,不需要我们自己去创建了,直接调用Spring提供的对象就可以了,这就是控制反转
2.面向切面编程(AOP)
在面向对象编程(OOP)中,我们将事务纵向抽成一个个的对象,而在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制,事务管理,日志记录等公用操作处理的过程,就是面向切面编程的思想。
IOC 什么含义
**Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。**在Java开发中,**Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。**如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
DI是什么?
I—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。**依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。**通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
- 谁依赖于谁:当然是应用程序依赖于IoC容器;
- 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
- 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
DI和IOC的区别
IOC:控制反转,把对象创建交给spring进行配置
DI:依赖注入,向类里面的属性中设置值
关系:依赖注入不能单独存在,需要在ioc的基础之上完成操作
属性注入的方式
Users.java
package kevin.demo.bean;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class Users {
private Integer userid;
private String username;
private String password;
public Users(String name,String pwd,Integer uid){
System.out.println("users带参构造方法。。。。");
this.userid = uid;
this.password=pwd;
this.username=name;
}
public Users(){
System.out.println("users无参构造方法。。。。");
}
public void say(){
System.out.println("hello,spring");
}
}
set方式注入:
beans.xml
<!--set注入:set方法-->
<bean id="users" class="kevin.demo.bean.Users" >
<property name="userid" value="1"></property>
<property name="username" value="admin"></property>
<property name="password" value="123456"></property>
</bean>
UsersTest.java
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Users users = context.getBean("users",Users.class);
System.out.println(users.getUserid()+"\t"+users.getUsername()+"\t"+users.getPassword());
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MpHPHFWP-1631611739840)(C:\Users\10690\AppData\Roaming\Typora\typora-user-images\image-20210913162740367.png)]
构造方式注入:
beans.xml
<!--构造子注入:构造函数-->
<bean id="users2" class="kevin.demo.bean.Users">
<constructor-arg name="name" value="root"></constructor-arg>
<constructor-arg name="pwd" value="147258"></constructor-arg>
<constructor-arg name="uid" value="2"></constructor-arg>
</bean>
UsersTest.java
@Test
public void test03(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Users users = context.getBean("users2",Users.class);
System.out.println(users.getUserid()+"\t"+users.getUsername()+"\t"+users.getPassword());
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-or3NfT3C-1631611739842)(C:\Users\10690\AppData\Roaming\Typora\typora-user-images\image-20210913162526488.png)]
Spring管理bean的作用域
- singleton(单实例)
Spring Bean 中所说的作用域,在配置文件中即是“scope”
<bean id="person" class="com.spring.Person" scope="singleton"></bean>
测试
@Test
public void test(){
// ApplicationContext是接口
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); // 实例化Spring容器
Person person1 =(Person)ctx.getBean("person");
Person person2 =(Person)ctx.getBean("person");
System.out.println(person1==person2);
}
结果是:true
说明了默认情况下bean交给Spring容器管理之后,这个bean就是一个单实例(单例模式)的,即每次调用getBean()方法,获取到的都是同一个bean实例。
- prototype
修改scope的值
<bean id="person" class="com.spring.Person" scope="prototype"></bean>
@Test
public void test(){
// ApplicationContext是接口
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); // 实例化Spring容器
Person person1 =(Person)ctx.getBean("person");
Person person2 =(Person)ctx.getBean("person");
System.out.println(person1==person2);
}
打印结果为:false
说明它们不是同一个实例,每getBean()方法都会产生新的实例
对于有状态的Bean应该使用prototype,对于无状态的Bean则使用singleton
- request
Request作用域针对的是每次的Http请求,Spring容器会根据相关的Bean的
定义来创建一个全新的Bean实例。而且该Bean只在当前request内是有效的。
- session
针对http session起作用,Spring容器会根据该Bean的定义来创建一个全新的Bean的实例。而且该Bean只在当前http session内是有效的。
- global session
Spring管理bean的生命周期
【1】实例化 Bean:对于 BeanFactory 容器,当客户向容器请求一个尚未初始化的 bean时,或初始化 bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean进行实例化。对于 ApplicationContext容器,当容器启动结束后,便实例化所有的单实例 bean。容器通过获取 BeanDefinition对象中的信息进行实例化。并且这一步仅仅是简单的实例化,并未进行依赖注入。实例化对象被包装在 BeanWrapper 对象中,BeanWrapper 提供了设置对象属性的接口,从而避免了使用反射机制设置属性。通过工厂方法或者执行构造器解析执行即可:创建的对象是个空对象。
【2】设置对象属性(依赖注入):实例化后的对象被封装在 BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。紧接着获取所有的属性信息通过 populateBean(beanName,mbd,bw,pvs),Spring 根据 BeanDefinition 中的信息进行依赖注入。并且通过 BeanWrapper提供的设置属性的接口完成依赖注入。赋值之前获取所有的 InstantiationAwareBeanPostProcessor 后置处理器的 postProcessAfterInstantiation() 第二次获取InstantiationAwareBeanPostProcessor 后置处理器;执行 postProcessPropertyValues()最后为应用 Bean属性赋值:为属性利用 setter 方法进行赋值 applyPropertyValues(beanName,mbd,bw,pvs)。
【3】bean 初始化:initializeBean(beanName,bean,mbd)。
-
执行xxxAware 接口的方法,调用实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口的方法。
-
执行后置处理器之前的方法:applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)所有后置处理器的 BeanPostProcessor.postProcessBeforeInitialization()
-
执行初始化方法: InitializingBean 与 init-methodinvoke 当 BeanPostProcessor的前置处理完成后就会进入本阶段。先判断是否实现了 InitializingBean接口的实现;执行接口规定的初始化。其次自定义初始化方法。
InitializingBean 接口只有一个函数:afterPropertiesSet()这一阶段也可以在 bean正式构造完成前增加我们自定义的逻辑,但它与前置处理不同,由于该函数并不会把当前 bean对象传进来,因此在这一步没办法处理对象本身,只能增加一些额外的逻辑。若要使用它,我们需要让 bean实现该接口,并把要增加的逻辑写在该函数中。然后 Spring会在前置处理完成后检测当前 bean是否实现了该接口,并执行 afterPropertiesSet函数。当然,Spring 为了降低对客户代码的侵入性,给 bean的配置提供了 init-method属性,该属性指定了在这一阶段需要执行的函数名。Spring 便会在初始化阶段执行我们设置的函数。init-method 本质上仍然使用了InitializingBean接口。
-
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);执行初始化之后的后置处理器的方法。BeanPostProcessor.postProcessAfterInitialization(result, beanName);
【4】Bean的销毁:DisposableBean 和 destroy-method:和 init-method 一样,通过给 destroy-method 指定函数,就可以在bean 销毁前执行指定的逻辑。
Bean 的管理就是通过 IOC 容器中的 BeanDefinition 信息进行管理的。
Spring中bean的两种方式
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
1、普通 bean:在配置文件中定义 bean 类型就是返回类型
lt, beanName);
【4】Bean的销毁:DisposableBean 和 destroy-method:和 init-method 一样,通过给 destroy-method 指定函数,就可以在bean 销毁前执行指定的逻辑。
Bean 的管理就是通过 IOC 容器中的 BeanDefinition 信息进行管理的。
Spring中bean的两种方式
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
1、普通 bean:在配置文件中定义 bean 类型就是返回类型
2、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样