Spring
Spring框架概述
- Spring是轻量级的开源JavaEE框架,他可以降低企业应用开发中的复杂性。
- Spring有两个核心组成部分,IOC和AOP
- IOC:inversion of control ,控制反转。即将创建对象和属性注入的过程交给Spring来管理。
- AOP:Aspect Oriented Programming,面向切面编程。可以在不修改源代码的基础上进行功能增强。
- Spring特点
- 方便解耦,简化开发
- AOP编程支持
- 方便程序测试
- 方便与其他框架进行整合
- 方便进行事务操作
- 降低API开发难度
Spring入门程序
引入Spring所需依赖(即导入jar包后),即可以开始设计Spring框架的入门程序。
创建普通类User
public class User{
public void add(){
System.out.println("ADD方法");
}
}
创建Spring配置文件:
<?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标签用于User对象创建 -->
<bean id="user" class="com.jarvis.bean.User"></bean>
</beans>
使用测试方法获取对象
@Test
public void test1(){
//获取应用程序上下文对象
ApplicationContext context = ClassPathXMLApplicationContext("bean.xml");
//使用应用程序上下文对象获取Bean对象
User user = context.getBean("user" , User.class);
user.add();
}
IOC(控制反转)
- 什么是IOC
IOC是指控制反转,即将对象创建和对象之间的调用过程交给Spring来处理,这样能够显著的降低程序的耦合性(即不需要再其他类中使用new创建对象) - IOC底层原理
IOC底层使用了XML解析技术、工厂原理和反射。<bean id="" class=""></bean>
,通过解析xml文件,来根据配置信息创建相应的工厂类- 通过工厂模式以及XML解析出的class属性值,通过反射的方法
Class clazz = Class.forName(classValue)
和clazz.newInstance()
创建目标对象
- IOC的BeanFactory接口
- IOC思想基于IOC容器完成,IOC容器就是对象工厂
- Spring中提供两种IOC容器的实现方式(两个接口)
- BeanFactory:IOC容器的基本实现,是Spring内部的使用接口,不提供开发人员使用。而且在加载xml配置文件时不会根据配置信息创建对象,只有在获取(使用)对象时才会创建对象(类似于懒汉式单例模式)
- ApplicationContext:应用程序上下文接口,是BeanFactory的子接口,功能更加强大,一般由开发人员使用。在加载配置文件时就会根据配置信息创建对象(类似于饿汉式单例模式)
- ApplicationContext接口的实现类有二:
- FileSystemXMLApplicationContext:根据盘路径解析XML配置文件
- ClassPathXMLApplicationContext:根据类路径解析XML配置文件
IOC的Bean管理
- Bean管理的概念
Spring中Bean管理的概念为Spring框架完成Bean对象的创建以及属性注入。Bean管理有两种实现方式,一种是基于XML配置文件的方式,另一种是基于注解的方式。 - 基于XML方式实现Bean管理
- 创建Bean对象
在xml文件中使用bean标签,如<bean id="" class="" ></bean>
。其中id属性是唯一标识,用于给Bean对象创建唯一标识,也是获取(创建)Bean的标识;class属性用于指明对象的全路径。在创建对象时默认使用newInstance()无参构造方法。 - 注入属性(DI,dependency injection,依赖注入,也即属性注入)
输入属性有三种实现方式:- 使用类的set方法注入,即在bean标签中使用property标签进行属性注入:
<property name="" value=""></prioperty>
,name属性需要和类中对应属性一致。 - 使用有参构造方法注入,即在bean标签中使用constructor-arg标签进行属性注入:
<constructor-arg name="" value=""></constructor-arg>
,name属性需要和类中有参构造方法中的参数一致 - p名称空间注入,在xml文件中引入p名称空间
<beans xmlns:p=""></beans>
,随后既可以在bean标签中使用p属性进行属性注入:<bean p:name1="value" p:name2="value2"></bean>
- 使用类的set方法注入,即在bean标签中使用property标签进行属性注入:
- 使用xml方式注入其他类型属性
- 字面量
(a) 注入null值:在property标签中加入null标签即可<property name=""></null></property>
(b) 属性值中包含特殊字符:在property标签中使用CDATA标签即可 - 外部bean
当需要注入的属性是同xml文件中的外部bean时,可以在property标签中使用ref属性取代value属性,属性值为该外部bean的id值<property name="" ref="外部bean的id值"></property>
- 内部bean
当需要注入的属性是引用数据类型时,可以使用内部bean的方式,即在property标签内部使用bean标签 - 级联赋值
- 字面量
- 使用xml注入集合属性
- 注入数组类型属性:可以在property标签内使用array标签来进行赋值
<property name=""><array><value>数组项</value></array></property>
- 注入list集合属性:和注入数组类似,将Array标签换为list标签即可
- 注入map集合属性:在property标签中使用map标签,在map标签中使用entry标签表示键值对,key属性和value属性填充键值对
- 在集合中设置对象类型值:在集合中如果集合项存在引用数据类型(即对象),可以使用外部bean的方式:
<list><ref bean="外部bean的id值"></ref><list>
- 把集合注入部分抽取出来,其中的数据信息可以供多个集合使用:
在配置文件中引入util名称空间,这样就可以使用util标签。将集合中的数据项放置在util标签内即可:
- 注入数组类型属性:可以在property标签内使用array标签来进行赋值
- 创建Bean对象
<util:list id="list1">
<value>数据项1</value>
<value>数据项2</value>
<value>数据项3</value>
</util>
<bean id="" class="">
<property name="list" ref="list1">
</property>
</bean>
- FactoryBean
Spring中的bean有两种:
- 第一种是普通bean,即上文所说的普通的java类。这种类在xml配置文件中class属性配置的类型和对象创建返回的类型是一致的,因此被称为普通bean
- 第二种是工厂bean,即FactoryBean。工厂Bean的特殊性在于在XML配置文件中class属性指向的是该工厂类Bean的全类名,而创建对象返回的结果却是该工厂类创建出的产品Bean。使用工厂Bean,需要创建一个集成FactoryBean接口的类,并将目标返回的对象类型放置到该接口的泛型中。实现该接口的getObject对象,即可获取到目标类对象。
public class MyBean implments FactoryBean<User>{
@Override
public User getObject() throws Exception{
User user = new User();
user.setName("jarvis");
return user;
}
}
//在xml文件中的配置为,只需要指向实现了工厂Bean接口的该类即可
<bean id="user" class="com.jarvis.bean.MyBean"></bean>
//在test测试使用时,可以发现返回的并不是MyBean类型,而是User类型
public void test(){
ApplicationConetxt context = new ClassPathXMLApplicationContext("bean.xml");
User user = context.getBean("user",User.class);
}
-
Bean的作用域
在Spring中可以设置创建好的Bean实例是单例还是多例。在默认情况下,使用IOC创建出的Bean是单例对象,即无论创建多少个对象引用,指向的都是唯一一个对象。
在bean标签中存在有scope属性,可以用于设置创建出的对象是单例还是多例:
<bean id="" class="" scope="singleton"></bean>
,singleton表示获取bean对象时会获得单例bean对象,prototype表示会获得多例对象。此外scope属性还有request
和session
等值,表示在bean对象创建好后会保存在哪个域中。 -
bean的生命周期
生命周期是指bean对象从对象创建到销毁的过程:- 构造器创建bean对象实例(使用无参构造方法)
- 为bean对象进行属性注入(使用set方法等)
- 调用bean对象的初始化方法(在bean标签中使用init-method属性设置)
- 实际使用时获取到bean对象,bean对象可以使用
- 调用bean对象的销毁方法(在bean标签中使用destroy-method属性设置)
class User{
public User(){}
public void initMethod(){}
public void destoryMethod(){}
}
//在xml中配置
<bean id="" class="" init-method="initMethod" destory-method="destoryMethod"></bean>
- bean的后置处理器
其实bean的生命周期还存在后置处理器,用于统一对所有bean对象进行操作,故bean的生命周期为:- 构造器创建bean对象实例(使用无参构造方法)
- 为bean对象进行属性注入(使用set方法等)
- 把bean实例传送到bean后置处理器的
postProcessorBeforeInitialization
方法进行处理 - 调用bean对象的初始化方法(在bean标签中使用init-method属性设置)
- 实际使用时获取到bean对象,bean对象可以使用
- 调用bean对象的销毁方法(在bean标签中使用destroy-method属性设置)
- 把bean实例传送到bean后置处理器的
postProcessorAfterInitialization
方法进行处理
添加后置处理器:创建BeanPostProcessor接口的实现类,并实现后置处理器的两个方法。而且需要在xml文件中设置该类的bean标签,来提交给Spring代理。
//实现beanPostProcessor接口
public class BeanPost() implments BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//执行后置处理器的操作
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//执行后置处理器操作
return bean;
}
}
//在xml文件中进行配置
<bean id="beanPost" class="com.jarvis.bean.BeanPost"></bean>
这样就可以对同一xml文件中生命的bean对象统一执行该后置处理器的操作。
- xml自动装配
自动装配是指根据指定的装配规则,由Spring自动将匹配的属性值进行注入(注意,自动注入的需要在同一配置文件中声明的bean)。
自动装配是由bean标签中的autowire属性实现的,有byName和byType两个值- byName:根据属性名称注入,注入值bean的id和类属性名称一致
- byType:根据属性类型注入,注入bean的class类型和类属性的类型一致
<bean id="emp" class="com.jarvis.beanEmp" autowire="byType">
<!-- <property name="" ref="dept"></property> -->
</bean>
<bean id="dept" class="com.jarvis.bean.Dept"></bean>
- 外部属性文件
xml配置文件也可以引入外部属性文件作为配置信息进行配置,这里以配置JDBC数据库连接为例:- 直接配置数据库信息
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/book"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
-
- 引入外部文件配置:首先需要引入context名称空间,随后就可以使用context标签引入外部文件,并使用Spring表达式配置数据信息
外部文件信息
prop.dirverClassName=com.mysql.jdbc.Driver
prop.url=http://localhost:3306/book
prop.username=root
prop.password=root
引入外部文件
<context:property-placeholder location="classpath:jdbc.properties">
使用外部文件
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.username}"></property>
<property name="url" value="http:localhost:3306/book"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
- 基于注解方式实现Bean管理
注解是代码的特殊标记,可以用于类、方法、属性甚至参数。使用注解,可以简化xml甚至代替xml配置文件
Spring中针对Bean管理创建对象提供了四个注解,这四个注解的功能一致,都可以用于Bean对象的创建- @Component(value=""):比较普通的注解,可用于所有bean对象的创建(valkue相当于xml文件中bean标签的id属性)
- @Service(value=""):用于Service层
- @Controller(value=""):推荐用于Web层
- @Repository(value=""):推荐用于DAO层
- 基于注解实现bean对象的创建
使用注解创建Bean对象,需要引入AOP依赖。此外,还要开启组件扫描,也即告知Spring,那些组件(包中的类)上存在注解,需要Spring来创建Bean对象。随后创建类并在类上添加注解即可。可以使用xml文件来进行组件扫描:
<context:component-scan base-package="需要扫描的组件包"></context:component-scan>
注意:组件扫描还可以对细节进行配置
use-default-filter属性:表示是否使用默认filter,默认为true
context:include-filter和context:exclude-filter标签可以设置指定过滤器扫描或者忽略指定的组件
<context:component-scan base-package="com.jarvis" use-default-filter="false"></context:component-scan>
//表示自定义的过滤器会只扫描带有该注解的类
<conetxt:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></conetxt:include-filter>
//表示自定义的过滤器会忽略带有该注解的类
<conetxt:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></conetxt:include-filter>
- 基于注解的方式实现属性注入
对于使用注解方式实现属性注入存在四个注解以供使用- @Autowired:根据属性类型进行自动装配
- @Qualifier:根据属性名称自动装配,该注解通常与Autowired一同使用
- @Resource:可以实现根据属性类型或者名称自动装配(在javax包中声明,作为java的扩展内容存在,因此Spring一般不推荐使用)
- @Value:用于注入基本数据类型的属性
@Component
public class User{
@Value(value="小明")
private String name;
@Value(value="123456")
private Integer id;
//@Autowired ---------------------------- 表示会根据类型注入,前提是该类需要由Spring实现自动创建
//@Qualifier(value="dept") -------------- 表示会根据名称注入
//@Resource ----------------------------- 表示会根据类型注入
//@Resource(value="dept") --------------- 表示会根据名称注入
private Dept department;
}
- 完全注解开发
由上文可知,使用注解来进行Bean管理需要开启组件扫描,而组件扫描需要以xml文件的形式实现。因此想要实现完全注解开发,只需要创建一个配置类代替xml文件开启组件扫描即可:
@Configuration //表示该类是用作配置类代替配置文件存在的
@ComponentScan(basePackages="com.jarvis")
public class ConfigurationClass{}
public void test(){
ApplicationContext context = AnnotationConfigApplicationContext(ConfigurationClass.class);
context.getBean(...);
}