spring
1.什么是spring
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。 轻量级:与EJB对比,依赖资源少,销毁的资源少。 分层: 一站式,每一个层都提供的解决方案
2.特点
1.方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
2.AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
3.声明事物的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4.方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
6.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
7.Java 源码是经典学习范例
3.优点
-
方便解耦,简化开发 (高内聚低耦合)
-
Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
-
spring工厂是用于生成bean
-
耦合性:也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。
-
-
AOP编程的支持
-
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
-
-
声明式事务的支持
-
只需要通过配置就可以完成对事务的管理,而无需手动编程
-
-
方便程序的测试
-
Spring对Junit4支持,可以通过注解方便的测试Spring程序
-
-
方便集成各种优秀框架
-
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
-
-
降低JavaEE API的使用难度
-
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
-
4.spring体系结构
Spring框架是一个分层架构,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation的测试部分,如图所示:
核心容器:beans、core、context、expression
5.spring核心主要两部分:
(1)aop:面向切面编程,扩展功能不修改源代码实现
(2)ioc:控制反转
5.1 ioc 控制反转
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们设计出松耦合、更优良的程序。把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
这里的控制指把控制权从应用程序中剥离出来。ioc它可以把创建对象和查找依赖对象的权限交给Ioc容器控制,而不是传统的由这些对象的使用方(消费者)进行创建初始化操作。IoC是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则。
为什么Ioc叫控制反转呢,反转了什么呢?传统的程序都是消费者主动创建对象,现在容器帮我们查找及注入依赖对象,而消费者只是被动的接受依赖对象,此为反转。
6.DI是什么?和ioc的区别
6.1DI:依赖注入
指容器复制创建和维护对象之间的依赖关系,而不是通过对象本身复制自己的创建和解决自己的依赖。控制反转是通过依赖注入实现的。
6.2DI和ioc区别与练习
(1)ioc 控制反转
传统资源查找方式:要求组件向容器发起请求,查找资源作为回应,容器适时返回资源。 IOC查找方式:容器主动将资源提供给它所管理的组件,组件只需要选择一个合适的方式来接收资源。 创建对象实例的控制权由代码控制转移到IOC容器控制(new关键字转移到容器),即在XML文件中控制,控制权转移即所 谓的反转,侧重于原理。 (2)DI:依赖注入(Dependecy Injection)
IOC另一种表达方式:组件以一些预先定义好的方式(如setter\getter)接收来自容器的资源注入。 相对于IOC,DI更直接。 创建对象实例时,为这个对象注入属性值和其他对象实例,侧重于实现。
7.属性注入方法
7.1 使用set方法进行注入
Dept.java
package com.syf.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id;
private String deptname;
private List<Emp> list;
}
Emp.java
package com.syf.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String name;
private int sex;
private Dept dept;
}
beans2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dept" class="com.syf.bean.Dept" >
<property name="id" value="001"></property>
<property name="deptname" value="创业部"></property>
</bean>
<bean id="emp" class="com.syf.bean.Emp">
<property name="id" value="1"></property>
<property name="name">
<!--属性值包含特殊符号
1.把<>进行转义
2.把带特殊符号的内容写到CDATA
-->
<value><![CDATA[《张三丰》]]></value>
</property>
<property name="sex" value="99"></property>
<property name="dept">
<ref bean="dept"></ref>
</property>
</bean>
</beans>
测试代码
@Test
public void test02() {
//获取配置文件 beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");
//配置文件的bean id
Emp emp=context.getBean("emp",Emp.class);
System.out.println(emp.getDept().getDeptname()+"\t"+emp.getId()+"\t"+emp.getName()+"\t"+emp.getSex());
}
结果截图:
构造方法注入:
Dept.java
package com.syf.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id;
private String deptname;
private List<Emp> list;
public Dept(Integer id, String deptname) {
this.id = id;
this.deptname = deptname;
}
}
Emp.java
package com.syf.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String name;
private int sex;
private Dept dept;
}
beans3.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dept1" class="com.syf.bean.Dept">
<constructor-arg name="id" value="002"></constructor-arg>
<constructor-arg name="deptname" value="公益部"></constructor-arg>
</bean>
<bean id="emp" class="com.syf.bean.Emp">
<constructor-arg name="id" value="02"></constructor-arg>
<constructor-arg name="name" value="刘嘉伟"></constructor-arg>
<constructor-arg name="sex" value="25"></constructor-arg>
<constructor-arg name="dept">
<ref bean="dept1"></ref>
</constructor-arg>
</bean>
</beans>
测试代码
@Test
public void test03() {
//获取配置文件 beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
//配置文件的bean id
Emp emp=context.getBean("emp",Emp.class);
System.out.println(emp.getDept().getDeptname()+"\t"+emp.getId()+"\t"+emp.getName()+"\t"+emp.getSex());
}
结果截图:
7.2集合属性的注入
ListTest:
package com.syf.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Map;
import java.util.Set;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ListTest {
private String[] arr;
private java.util.List<String> list;
private Map<Integer,String> map;
private Set set;
}
beans4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="list" class="com.syf.bean.ListTest" >
<property name="arr">
<array>
<value>I</value>
<value>Am</value>
<value>Iron</value>
<value>Man</value>
</array>
</property>
<property name="list">
<list>
<value>I</value>
<value>Am</value>
<value>Iron</value>
<value>Man</value>
</list>
</property>
<property name="map">
<map>
<entry key="1" value="I"></entry>
<entry key="2" value="Am"></entry>
<entry key="3" value="Iron"></entry>
<entry key="4" value="Man"></entry>
</map>
</property>
<property name="set">
<set>
<value>I</value>
<value>Am</value>
<value>Iron</value>
<value>Man</value>
</set>
</property>
</bean>
</beans>
测试:
@Test
public void test04() {
//获取配置文件 beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans4.xml");
//配置文件的bean id
ListTest list=context.getBean("list", ListTest.class);
System.out.println(list.getArr());
System.out.println(list.getList());
System.out.println(list.getMap());
System.out.println(list.getSet());
结果截图:
8.Spring管理的bean的作用域有
8.1 singleton
在每个Spring IoC容器中,一个bean定义只有一个对象实例。
Car.java
package com.syf.bean;
public class Car {
private String brand;
private String corp;
private double price;
private int maxpeed;
public Car(String brand, String corp, double price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
public Car() {
}
public String getBrand() {
return brand;
}
public String getCorp() {
return corp;
}
public double getPrice() {
return price;
}
public int getMaxpeed() {
return maxpeed;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setCorp(String corp) {
this.corp = corp;
}
public void setPrice(double price) {
this.price = price;
}
public void setMaxpeed(int maxpeed) {
this.maxpeed = maxpeed;
}
}
Person.java
package com.syf.bean;
public class Person {
private Car car;
public Person(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.syf.bean.Car">
<property name="brand" value="帕萨特"></property>
<property name="corp" value="大众"></property>
<property name="price" value="5000"></property>
</bean>
<bean id="persion" class="com.syf.bean.Person">
<constructor-arg name="car">
<ref bean="car"></ref>
</constructor-arg>
</bean>
</beans>
测试
@Test
public void test05() {
//获取配置文件 beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//配置文件的bean id
Person person1 = context.getBean("persion", Person.class);
Person person2 = context.getBean("persion", Person.class);
Person person3 = context.getBean("persion", Person.class);
System.out.println(person1==person2&&person1==person3);
}
最后,测试test05()方法,控制台输出true,说明了默认情况下bean交给Spring容器管理之后,这个bean就是一个单实例(单例模式)的,即每次调用getBean()方法,获取到的都是同一个bean实例。
结果截图:
8.2prototype
每次从容器获取bean都是新的对象
实体类 测试都和singleton相同
beans.xml更改后
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.syf.bean.Car">
<property name="brand" value="帕萨特"></property>
<property name="corp" value="大众"></property>
<property name="price" value="5000"></property>
</bean>
<bean id="persion" class="com.syf.bean.Person" scope="prototype">
<constructor-arg name="car">
<ref bean="car"></ref>
</constructor-arg>
</bean>
</beans>
结果截图为:
最后,测试test05()方法,控制台输出flase,就已经证实了若bean的作用域置为prototype,那么每次从Spring容器获取bean都将是新的对象。
9.Spring Bean 的生命周期
9.1 五步
1.构造方法
2.set方法
3.初始化方法
4.bean可以使用
5.销毁方法
BeanLife.java
package com.syf.bean;
public class BeanLife {
public String name;
public BeanLife() {
System.out.println("无参调用了");
}
public void setName(String name) {
this.name = name;
System.out.println("Set方法执行了");
}
public String getName() {
System.out.println("Get方法执行了");
return name;
}
public void init(){
System.out.println("init方法执行了");
}
public void dertory(){
System.out.println("dertory方法执行了");
}
}
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean" class="com.syf.bean.BeanLife" init-method="init" destroy-method="dertory">
<property name="name" value="李四"></property>
</bean>
</beans>
测试:
@Test
public void test06() {
//获取配置文件 beans.xml
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans5.xml");
System.out.println("-------加载配置文件-----------");
//配置文件的bean id
BeanLife beanLife=context.getBean("bean",BeanLife.class);
System.out.println("-----------Spring获取对象--------");
context.close();
}
结果截图:
七步:
1.构造方法
2.set方法
3.初始化之前执行
4.初始化方法
5.初始化之后执行
6.bean可以使用
7.销毁方法
新建BeanLife.java实现接口BeanPostProcessor 重写方法 postProcessBeforeInitialization和postProcessAfterInitialization
package com.syf.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanLife2 implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前执行了");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后前执行了");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
bean5更改后:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean" class="com.syf.bean.BeanLife" init-method="init" destroy-method="dertory">
<property name="name" value="李四"></property>
</bean>
<bean id="bean1" class="com.syf.bean.BeanLife2"></bean>
</beans>
测试和前面一致:
结果截图:
10.Spring的两种bean
普通bean:在配置文件中定义bean类型就是返回类型
工厂bean:在配置文件中定义bean类型可以与返回类型不一致 ,返回类型与实现接口式类型一致
10.1 普通bean
1.创建类
package com.syf.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id;
private String deptname;
private List<Emp> list;
}
2.写bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dept1" class="com.syf.bean.Dept">
<constructor-arg name="id" value="002"></constructor-arg>
<constructor-arg name="deptname" value="公益部"></constructor-arg>
</beans>
测试
@Test
public void test03() {
//获取配置文件 beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
//配置文件的bean id
Dept dept=context.getBean("dept",Dept.class);
System.out.println(dept.getDeptname());
}
10.2 工厂bean
1.创建类MyFactoryBean 实现接口FactoryBean
package com.syf.bean;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<Dept> {
@Override
public Dept getObject() throws Exception {
return null;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
2.bean写入xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myFactoryBean" class="com.syf.bean.MyFactoryBean"></bean>
</beans>
3.测试
@Test
public void test07() {
//获取配置文件 beans.xml
ApplicationContext context = new ClassPathXmlApplicationContext("beans6.xml");
//配置文件的bean id
Object obj=context.getBean("myFactoryBean",Dept.class);
System.out.println(obj);
}
4.结果