Spring框架
SSM作为现在主流开发框架,是每个后端开发人员不得不学的东西,本文适合SSM框架入门,但是在此之前,你需要有一定的基础知识,如果您还不是很了解后台开发,请参见孤傲沧浪的博文,对于后台开发的基础知识讲解比较好。http://www.cnblogs.com/xdp-gacl/tag/JavaWeb%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93
本部分内容主要介绍Spring的知识,内容包括整理互联网教材等,仅作交流,不涉及版权。参考资料为《JavaEE企业级应用开发教程(SSM)》【很好的一本书】《以及javaEE互联网轻量级框架整合与开发》很厚,适合作为参考资料。
1.1 Spring优点
轻量:Spring 是轻量的,基本的版本大约2MB。
控制反转IOC:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
容器:Spring 包含并管理应用中对象的生命周期和配置。
MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。
1.2 Spring入门及注解
Spring体系架构
· Core container
Spring最核心的容器,提供Spring框架的基本功能,包含beans、core、Context、context-support、SpELl五大模块,最主要组件是Beans中的BeanFactory,以及Core,它实现了IOC和DI,将APP的配置和依耐性规范与实际应用代码分离。Context是定义和访问配置任何对象的媒介。context-support提供了对第三方库嵌入Spring的支持,SpEL支持EL表达式。
·DataAccess
包括Jdbc、ORM、OXM、JMS以及Transaction,主要用于简化那些比较难操作的API,同时支持映射、实务及消息传递。
· WEB模块
支持Servlet以及websock、web和Portlet。
· 其他模块
有AOP、aspect以及messaging模块。
快速入门
下载好的Spring框架主要包含三类文件RELEASE.jar、RELEASE—Javadoc.jar、RELEASE-source.jar,分别是框架class文件(我们要用的)、API文档以及框架的源文件。
建立java web工程需要用到core container容器,这个直接去官网搜索(省略),需要导入以下几个包:
spring-beans-XXX-RELEASE.jar(所有应用都会用到,包含配置文件,创建和管理bean,IOC以及DI操作)
spring-context-XXX-RELEASE.jar(IOC扩展服务,提供很多企业级服务支持)
spring-core-XXX-RELEASE.jar(框架最核心的工具类)
spring-expression-XXX-RELEASE.jar(框架的表达式语言)
spring-AOP-XXX-RELEASE.jar(切面编程需要的包)
同时需要导入开发的日志记录包,可以从Tomcat的lib目录下找到:
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
常用注解:
(1)实体创建类注解
a) @Component 为通用注解
b) @Repository 为持久层组件注解
c) @Service 为业务层组件注解
d) @Controller 为控制层注解
(2)实体属性注解
@Scope 为Bean的作用域注解,
@Value 为注入Spring表达式值的注解
(3)依赖关系注解
@Autowired 为指定Bean之间依赖关系的注解
@Inject 为指定Bean之间依赖关系的注解
(4)数据传输注解
@ResponseBody 为Ajax返回类型的注解
1.3 Spring常用概念
IOC类型
(1) 基于特定接口(侵入式方案)
(2) 基于set方法
(3) 基于构造器
第一种类型示例如下,一个典型应用就是HttpcontextServlet
eg:
public class A {
private InterfaceB B;
public void done() {
Ojbect obj=Class.forName(BImpl).newInstance();
B = (InterfaceB)obj;
B.doIt()
}
A依赖于InterfaceB,由预先在配置文件中设定的接口的实现类名,动态加载实现类,并通过InterfaceB强制转型。但是这种注入方法很少出现在现在的代码中,早期代码使用较多,基本可以不理会。
Spring容器
Spring容器负责生成、组装、销毁组件,并负责事件处理等功能。
(1) BeanFactory
① 核心容器,负责组件生成和装配
② 实现主要包括Xml BeanFactory
xmlBeanFactory:BeanFactory的一个实现,使用Resource对象来查找配置文件,同时也是最常用的实现
BeanFactory.gerBean(“BeanId”):取得以参数命名,或者Id等于参数值的一个Bean实例。
BeanFactory(容器)在默认情况下,会采用单例方式返回对象。容器只到调用getBean方法时,才会实例化某个对象。
采用BeanFactory获取配置文件方法如下,但是这种方法大部分公司已经不再使用。
Resource resource=new ClassPathResource(“filename”);
BeanFactory factory =new XmlBeanFactory(resource);
(2)ApplicationContext
BeanFactory实现了IOC,而ApplicationContext扩展了BeanFactory并添加了对国际化和生命周期实践的发布监听等强大功能。和BeanFactory区别在于,后者会在初始化时自检是否注入了依赖属性。主要包含下述三个实现类:
(1)ClassPathXmlApplicationContext
从当前路径检索配置文件,并加载来创建容器。
ApplicationContext context = new ClassPathXmlApplicationContext(“filename”);
(2)FileSystemXmlApplicationContext
该类不从路径获取配置文件,通过参数指定配置文件的位置(必须是绝对路径,因此不推荐使用该方法,限制了程序的灵活性),可以获取资源路径之外的资源。
ApplicationContext context = new FileSystemXmlApplicationContext(“filenpath”);
(3)WebApplicationContext
该类是Spring的web应用容器,在Servlet中使用包括两种方式,这种方式一般在配置文件中直接配置,由服务器完成实例化。
A.在servlet的web.xml文件中配置Spring的ContexLoaderListener监听器
B.修改web.xml文件,在其中添加一个Servlet,定义使用Spring的org.springframework.web.contex.ContexLoaderServlet类。
实例:
Bean的获取
在创建Spring容器后,第一种方法是通过getBean(String name)方法获取bean,name属性可以是BeanID或者BeanName;第二种方法通过<T> T getBean(Class<T> requiredType)来获取(类类型获取)。
多配置文件加载
Spring支持xml和properties文件两种配置方式,但是常用的是xml方式。在加载配置文件的过程中可能遇到多个配置文件,处理方法如下:
第一种写法,数组参数传入:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml",”bean2.xml”);
第二种方法,在源文件中导入,此时只需要加载主文件即可:
<import resource="applicationContext2.xml"/>
第三种方法,使用*通配符:
ApplicationContext contex=new ClassXmlApplicationContext("a*.xml");
但此种方法只对文件系统中的xml文件有效,针对jar包中的无效
当然你也可以在web.xml文件中加载这些配置文件,然后通过Servlet来处理Spring请求。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/db-pub.xml,
classpath:bean*.xml,classpath*:timer-system.xml
</param-value>
</context-param>
DI(Dependency Injection,依赖注入)
简单来说,一个系统中可能会有成千上万个对象。我们可以在Spring的XML文件描述它们之间的关系,由Spring自动来注入它们——比如A类的实例需要B类的实例作为参数set进去。通俗的说,以前需要调用一个对象时,我们要先new出其实例,但是有了Spring,他会创建被调用的对象,作为调用者,我们只需要被动的接收Spring传来的对象就行了。这个过程既包含控制反转又包含依赖注入。
AOP(Aspect Oriented Programming,面向切面编程)
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。将程序中的交叉业务逻辑提取出来,称之为切面。将这些切面动态织入到目标对象,然后生成一个代理对象的过程。
1.4Bean对象的操作
Bean的生命周期
· 配置Bean的初始化和销毁的方法:在xml文件中加入:
· init-method=”setup”
· destroy-method=”teardown
执行销毁的时候,必须手动关闭工厂,而且只对scope=singleton有效,必须用子类执行 ClassPathXmlApplicationContext 中的close方法来实现。
注解方式
@PostConstruct : 初始化
@PreDestroy : 销毁
Bean的生命周期的11个步骤
1 . bean对象实例化 : instantiate bean
2 . 属性的注入: populate properties : 封装属性
3 . 注入配置的类的名称 : 如果Bean实现BeanNameAware 执行 setBeanName
4 . 注入applicationContext : 如果Bean实现BeanFactoryAware 或者 k 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
5 . 初始化之前执行操作 : 如果存在类实现 BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization 需要添加此标签:
<bean class="cn.itcast.spring3.demo4.MyBeanPostProcessor"></bean>
6 . 属性设置后执行操作 : 如果Bean实现InitializingBean 执行 afterPropertiesSet
7 . 调用手动设置的初始化方法 : 调用<bean init-method="init"> 指定初始化方法 init
8 . 初始化后执行操作 : 如果存在类实现 BeanPostProcessor(处理Bean),执行 postProcessAfterInitialization
9 . 执行业务处理
10 . 调用销毁的方法 : 如果Bean实现 DisposableBean 执行 destroy
11 . 调用手动销毁方法 : 调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy
后处理器
在Spring构造Bean对象过程中,有一个环节对Bean对象进行后处理操作,pring 提供 BeanPostProcessor 接口 可以自定义类,实现 BeanPostProcessor 接口,配置到Spring容器中,在构造对象时,spring容器会调用接口中方法,是AOP自动代理核心 !
实现如下:
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.out.println("后处理器 初始化后执行...");
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
// 针对bean id 为 lifeCycleBean的对象 进行代理
if (beanName.equals("lifeCycleBean")) {
System.out.println("后处理器 初始化前执行...");
return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理.....");
return method.invoke(bean, args);
}
});
}
return bean;
}
}
(1)id属性:用于指定配置对象的名称,不能包含特殊符号。
(2)class属性:创建对象所在类的全路径。(3)name属性:功能同id属性一致。但是在name属性值中可以包含特殊符号。 且name属性可以重复出现,后面的name属性覆盖前面的属性。
(4)scope属性
singleton : 单例的(默认的值),Spring容器只创建一个共享的bean,所有对bean的请求,只要id与他匹配,就返回它的一个实例,可以用于Dao组件和Service组件。
prototype : 多例的,每次都会返回一个实例
request : web开发中创建了一个对象,将这个对象存入request范围,request.setAttribute();
session : web开发中.创建了一个对象,将这个对象存入session范围,session.setAttribute();
globalSession :一般用于Porlet应用环境.指的是分布式开发.不是porlet环境,globalSession等同于session;
实际开发中主要使用 singleton,prototype
Bean实例化的方式
主要包含:构造方法实例化、静态工厂实例化、实例工厂实例化,基于配置文件的实例化。
无参数构造方法的实例化
<!-- 默认情况下使用的就是无参数的构造方法. -->
<bean id="bean1" class="cn.itcast.spring.Bean1"></bean>
静态工厂实例化 – 简单工厂模式
<!-- 第二种使用静态工厂实例化 -->
<bean id="bean2" class="cn.itcast.spring.Bean2Factory" factory-method="getBean2"></bean>
实例工厂实例化 – 工厂方法模式
<!-- 第三种使用实例工厂实例化 -->
<bean id="bean3Factory" class="cn.itcast.spring.Bean3Factory"/>
<bean id="bean3"factory-bean="bean3Factory"factory-method="getBean3"></bean>
属性注入
属性注入指创建对象时,向类对象的属性设置属性值。在Spring框架中支持set方法注入(必须有无参的构造函数)、有参构造函数注入以及p名称空间注入属性。具体来说就是创建对象后通过set方法设置属性、采用有参构造函数创建对象并初始化属性或者用类似于C++的方式设置。
A.基于xml文件配置注入
(1)P空间注入
若要支持P命名空间则需要引入:xmlns:p="http://www.springframework.org/schema/p"
p:<属性名>="xxx" 引入常量值
p:<属性名>-ref="xxx" 引用其它Bean对象
<bean id="car" class="cn.itcast.spring.Car" p:name="豪车" p:price="100000000000000000"/>
<bean id="person" class="cn.itcast.spring.Person" p:name="minlay" p:car-ref="car"/>
(2)set方法注入
这种注入方法最为常见,依赖于构造器。
<property name="name" value="Teacher"></property>
<property name="name" ><value>Teacher</value></property>
(3)有参构造函数注入
多个参数注入的情况分别如下:
<constructor-arg index=“1”type="String" value="Boy"></constructor-arg>
<constructor-arg index=“2” type="char" value="M"></constructor-arg>
<constructor-arg name="age" value="13"></constructor-arg>
<constructor-arg name="name" value="Boy"></constructor-arg>
一个参数的构造函数实现注入的方法:
<constructor-arg name="age" value="14"></constructor-arg>
<constructor-arg name="name" ><value>Teacher</value></constructor-arg>
配置文件实例模板:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--定义Bean -->
</beans>
SpEL:属性的注入
语法:<bean id="IDnum" value="#{表达式}">
#{'神回复:哈哈'}使用字符串
#{BeanID} 使用另一个bean
#{BeanID.content().toUpperCase()} 使用指定名属性,并使用方法
#{T(java.lang.Math).PI} 使用静态字段或方法
B.基于注解的注入方式
@Component的3个衍生注解,其功能就目前来说是一致的,均是为了创建对象。且注解不可用于接口,因为接口不能被实例化。
@Controller :WEB层
@Service :业务层
@Repository :持久层
以单例或多实例方式创建对象,默认为单例,多例对象设置注解如下:
@Component(value="user")
@Scope(value="prototype")
注:配置文件和注解混合使用
1)创建对象的操作一般使用配置文件方式实现;
2)注入属性的操作一般使用注解方式实现。
对象属性
@Autowired用于对bean的属性变量、属性的setter方法、构造方法进行标注,配合对应注解处理器完成bean的自动装配,默认按照bean的类型进行装配。通过@Autowired的required属性,设置一定要找到匹配的Bean,默认为true,为false时表示对异常不关心。@Qualifier指定注入Bean的名称,使用Qualifier 指定Bean名称后,注解Bean必须指定相同名称。 @Qualifier配合@Autowired使用,制定bean实例名称
@Resource作用与@Autowired一样,只是他按照bean实例名称进行装配。name属性解析为bean的实际名称,type解析为bean的实例类型,若无法匹配抛出异常。
普通属性
@Value(value=”itcast”)private String info;
标准注解
@Autowired@Qualifier("userDao")
private UserDao userDao;
@Resource(name="userDao")
private UserDao userDao
实际使用中,一般将注解和xml配置相结合,采用xml配置方式注册Bean,用注解方式实现属性注入。具体应用可以参考https://blog.csdn.net/lutianfeiml/article/details/51731219,总结很详细。
注解的实例:
package cn.testSpring.dao;
import org.springframework.stereotype.Repository;
@Repository(value="userDao")
public interface UserDao {
void add();
}
package cn.testSpring.dao.impl;
import org.springframework.stereotype.Repository;
import cn.testSpring.dao.UserDao;
@Repository(value="userDao")
public class UserDaoImpl implements UserDao {
/* (non-Javadoc)
* @see cn.testSpring.dao.impl.UserDao#add()
*/
@Override
public void add() {
System.out.println("UserDao Add Method.");
}
}
package cn.testSpring.service;
import org.springframework.stereotype.Service;
@Service(value="userService")
public interface UserService {
void add();
}
package cn.testSpring.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import cn.testSpring.dao.UserDao;
import cn.testSpring.service.UserService;
@Service(value="userService")
public class UserServiceImpl implements UserService {
@Resource(name="userDao")
private UserDao userDao;
@Override
public void add() {
System.out.println("UserService Add Method.");
userDao.add();
}
}
package cn.testSpring.junitTest;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.testSpring.service.UserService;
class UserServiceTest {
@Test
void testAdd() {
System.out.println("开始测试!!!");
ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
使用Java类提供Bean定义信息
@Configuration 指定POJO类为Spring提供Bean定义信息,代表此类就是一个配置类。
@Bean 提供一个Bean定义信息
@Configuration
public class BeanConfig {
@Bean(name="product")
public Product initProduct(){
Product product = new Product();
product.setName("产品");
product.setPrice(100000);
return product;
}
}
使用注解在Spring3.0之前依旧需要在配置文件中实例化bean,但是在spring3.0之后,直接通过;
<context: component-scan base-package="基包名">在此之前需要导入aop包不然会报错。