javaweb开发中,几乎离不开各种开源框架的支持。
javaweb的开发分为三个层次:
WEB层 (表现层)
业务层 – Bean管理:(IOC)
持久层 – Spring的JDBC模板.ORM模板用于整合其他的持久层框架
在这三个层次中,常用的框架结构有SSH和SSM。无论是SSH还是SSM,业务层都是由Spring来实现的。因此,Spring框架对于javaweb开发非常重要。1.Spring简介
- Spring是一个开源框架
- Spring是于2003 年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
- 它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。
- Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以 从Spring中受益。
1.1 Spring的特点
* 方便解耦,简化开发
* Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
* AOP编程的支持
* Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
* 声明式事务的支持
* 只需要通过配置就可以完成对事务的管理,而无需手动编程
* 方便程序的测试
* Spring对Junit4支持,可以通过注解方便的测试Spring程序
* 方便集成各种优秀框架
* Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持
* 降低JavaEE API的使用难度
* Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
2.Spring之IoC技术简介
IoC(Inverse of Control),控制反转,将对象的创建权反转给Spring,解决程序耦合性高的问题。
平常的开发中,我们创建一个对象,必须使用new这个关键词来完成。在javaweb的三层开发结构中,三个不同的层次的类之间进行调用。如果都使用new这个关键字来创建对象的实例。那么程序的耦合性会非常高,后期维护会很麻烦。
Spring的IoC技术,帮开发者创建和管理对象。只需要在配置文件中引入先关类的全路径,那么Spring会通过反射来帮助我们创建对象。我们不需要new对象,便可以安安心心的使用了。
2.1 需要导入的jar包
具体的jar包可以去spring的官网或者一些开源社区上去下载。其中第一个包是日志的jar包。
3. 代码实现IoC
创建两个测试类,一个是service层的类,一个是dao层的类。service层测类调用dao层的类。一般开发中,这两个类最好各自实现自己的接口,方便解耦。
public class MydaoImpl implements Mydao {
public void save() {
System.out.println("这里是持久层");
}
}
public class MyServiceImpl implements MyService {
private MydaoImpl myDao;
private String name;
private int age;
private ArrayList<String> list;
public void setList(ArrayList<String> list) {
this.list = list;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setMyDao(MydaoImpl myDao) {
this.myDao = myDao;
}
@Override
public void saveUser() {
System.out.println("业务层保存用户");
}
public void printInfo(){
System.out.println("age-"+age+"name-"+name);
}
public void testDI(){
myDao.save();
}
public void printList(){
for (String str : list) {
System.out.println(str);
}
}
}
3.1 spring实现IoC的配置文件
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myservice" class="com.mq.service.MyServiceImpl">
</bean>
</beans>
该xml的名称为applicationContext.xml,名称可以改,但一般都为applicationContext。一般放在src目录下。
每一个需要被管理的类,放在在bean标签中进行配置,class是该类的全路径。id是给该类设置一个唯一的标志。
3.2 测试
public class MyTest {
@Test
public void f1(){
// 使用Spring的工厂:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类:
MyServiceImpl userService = (MyServiceImpl) applicationContext.getBean("myservice");
userService.saveUser();
}
}
测试结果:
11:49:19,413 INFO ClassPathXmlApplicationContext:578 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@46f5f779: startup date [Fri Jul 14 11:49:19 CST 2017]; root of context hierarchy
11:49:19,464 INFO XmlBeanDefinitionReader:317 - Loading XML bean definitions from class path resource [applicationContext.xml]
业务层保存用户
在调用MyServiceImpl的saveUser方法中,没有创建MyServiceImpl的实例,就可以直接调用该方法了。因为Spring已经帮我们创建了该类的实例对象。
这就是一个最简单的Spring实现IoC的例子。
4. DI
DI ( Dependency Injection),依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!
最常见的场景是,A类需要调用B类的方法,B类是A类的成员属性。并且要提供set方法。首先A类和B类都必须在applicationContext.xml配置文件中进行配置。
在MyServiceImpl有三个属性,其中myDao是一个类的引用。这种形式在开发中非常常见。具体代码上面已经给出。
4.1 依赖注入的配置文件
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myservice" class="com.mq.service.MyServiceImpl">
<property name="name" value="张三"/>
<property name="age" value="15"/>
<property name="myDao" ref="mydao"></property>
</bean>
<bean id="mydao" class="com.mq.dao.MydaoImpl">
</bean>
</beans>
对于MydaoImpl和MyServiceImpl都进行了配置。在bean标签下,有property子标签,该标签就是用来配置依赖注入的。
property标签中,name表示在该类中的属性名称,该值必须和MyServiceImpl的属性一致。value表示给该属性赋值,如果该属性是基础类型或者String类型的话。ref表示引用。后面必须是另外一个已经配置的类的id值。
简而言之,在property标签中,name表示属性。如果属性是包括String类型在内的基础类型,使用value直接进行赋值。如果是该属性是其他类的引用,那么就使用ref。
测试结果:
public class MyTest {
@Test
public void f1(){
// 使用Spring的工厂:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类:
MyServiceImpl userService = (MyServiceImpl) applicationContext.getBean("myservice");
//userService.saveUser();
userService.printInfo();
userService.testDI();
}
}
12:12:09,241 INFO ClassPathXmlApplicationContext:578 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@52d455b8: startup date [Fri Jul 14 12:12:09 CST 2017]; root of context hierarchy
12:12:09,287 INFO XmlBeanDefinitionReader:317 - Loading XML bean definitions from class path resource [applicationContext.xml]
age-15name-张三
这里是持久层
可见,MyServiceImpl中,我们没有new MyDaoImpl的实例对象,就可以调用MyDaoImpl的方法。
4.2 构造方法注入
这种方式用到的不是特别多,需要提供构造方法。
public class Fruit {
private String name;
private double money;
public Fruit (String name, double money) {
this.name = name;
this.money = money;
}
}
依赖注入的配置文件内容:
<bean id="fruit" class="com.mq.bean.Fruit">
<constructor-arg name="name" value="香蕉"/>
<constructor-arg name="money" value="100"/>
</bean>
4.3数组集合和Properties的注入
以list集合为例,在MyServiceImpl中声明list属性,并且提供set方法。
配置文件中:
<bean id="myservice" class="com.mq.service.MyServiceImpl">
<property name="name" value="张三"/>
<property name="age" value="15"/>
<property name="myDao" ref="mydao"></property>
<property name="list">
<list>
<value>吃饭</value>
<value>睡觉</value>
</list>
</property>
</bean>
其中, 中的内容,就是赋给集合中的元素。
4.3.1 其他集合的注入方式
2. 如果是Set集合,注入的配置文件方式如下:
<property name="set">
<set>
<value>上班</value>
<value>下班</value>
</set>
</property>
3. 如果是Map集合,注入的配置方式如下:
<property name="map">
<map>
<entry key="香蕉" value="3.8"/>
<entry key="橘子" value="2"/>
<entry key="苹果" value="1"/>
</map>
</property>
4. 如果是properties属性文件的方式,注入的配置如下:
<property name="pro">
<props>
<prop key="name">root</prop>
<prop key="password">test</prop>
</props>
</property>
5. Spring的其他标签的配置
bean标签中,除了最为常见的id和class子标签,还有其他标签。
- name:给Bean起个名字。如果没有设置id标签,name可以当做id来使用。
- scope:代表Bean的作用范围。有五个取值。
* singleton -- 单例(默认值)。
* prototype -- 多例,整合Struts2中,Action类是多例的,必须设置此属性。
* request -- 应用在Web项目中,每次HTTP请求都会创建一个新的Bean
* session -- 应用在Web项目中,同一个HTTP Session 共享一个Bean
* globalsession -- 应用在Web项目中,多服务器间的session
- init-method:创建bean时调用init-method指定的方法
- destroy-method:销毁该bean的实例事调用其指定的方法。
6. 其他
目前都只是在测试的方法中加载applicationContext.xml文件。每执行一次测试的方法,都需要重新加载配置文件,效率会比较低。
在web开发中,也不建议来一次请求,就先加载applicationContext.xml文件,再执行相应的方法。这样效率会非常低。
最好的方法时,在ServletContext创建的时候就加载该配置文件,不用每次请求来了都去加载。因此,需要一个listener进行监听ServletContext的创建。
第一步:首先需要导入spring-web-4.2.4.RELEASE.jar包。
第二步:配置监听器:
<!-- 配置Spring的核心监听器: -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
第三步:在请求的方法中使用Bean
WebApplicationContext applicationContext =WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
MyServiceImpl myservice= (MyServiceImpl) applicationContext.getBean("myservice")
myservice.testDI();
这样,只有在项目启动的时候才会加载配置文件,我们直接在web层的接收请求的方法中,可以通过applicationContext对象直接获取相应的bean对象。