Spring(一)

具体内容
3.1、Spring的作用
之前的开发模式:Struts + Hibernate,由Hibernate完成具体的数据库操作,但是开发者在开发中就必须不断的处理一些与具体业务无关的操作,例如:Session的打开与关闭、事务处理等,那么实际上这些与业务无关的操作又决定了程序的最终运行效果,如果不关闭数据库,则程序到一定程度就无法再继续使用了。
业务逻辑层由Spring去做,整合前台和后台数据库间的互操作。
要创建一个类的实例化对象有多少种方法?
• 直接使用new关键字,最直接的做法。
• 通过Class创建
• 对象克隆
• 对象引用传递。
使用new直接实例化对象则会加深耦合度,如果使用工厂解耦合的话,如果一个项目中的接口过多,则会造成工厂过大,维护并不方便,而且修改子类的时候也需要修改工厂。
设计原则:
• 高层模块不应该依赖于底层模块,二者都应该依赖于抽象
• 抽象不应该依赖于细节,细节应该依赖于抽象
• 依赖于抽象的具体方式
1、任何变量都不应该持有一个指向具体类的指针或者引用
2、任何类都不应该从具体的类派生
3、任何方法都不应该覆写它的任何基类中的已经实现了的方法

Spring的组成模块是非常多的,而且本身在设计的时候就相当于把大部分的开源项目完全的整合在了一起。
Spring管理ORM是整个Spring的一个重点,它会负责事务的处理、数据库的打开与关闭。
Spring本身完全是针对于接口的编程,如果要想使用Spring接口是必不可少的。
使用MyEclipse进行Spring的开发。


表示定义Spring的核心配置文件,文件名称一般都默认为:applicationContext.xml,此名称可以修改,但是不建议这样使用。
例如:定义以下的一个接口:
package org.lxh.simple;
public interface Hello {
public String sayHello() ;
}
有接口之后应该定义子类,子类要实现此接口
例如:定义接口的子类 —— 得到大写的内容
package org.lxh.simple.impl;
import org.lxh.simple.Hello;
public class HelloUpperImpl implements Hello {
public String sayHello() {
return "HELLO WORLD!!!";
}
}
例如:定义接口的子类 —— 得到小写的内容
package org.lxh.simple.impl;
import org.lxh.simple.Hello;
public class HelloLowerImpl implements Hello {
public String sayHello() {
return "hello world!!!";
}
}
如果按照之前的做法,此时应该定义的是一个工厂类,但是现在有了Spring之后不用再单独定义工厂类了,所有的内容通过Spring的配置文件 —— applicationContext.xml进行统一的管理。
<bean id="hello"  注册一个bean的名称
class="org.lxh.simple.Hello"  此bean对应的包.类名称
abstract="true"></bean>  此bean是一个抽象的是不能被实例化的
<bean id="hellolower"  注册一个bean的名称
class="org.lxh.simple.impl.HelloLowerImpl"
parent="hello">  此bean的父类或父接口是那一个bean(要求必须在文件中存在)
</bean>
<bean id="helloupper"
class="org.lxh.simple.impl.HelloUpperImpl"
parent="hello">
</bean>
以上的程序代码通过配置文件完成之后,以后在程序中就不再需要new关键字实例化,而是通过Spring自动进行实例化操作。
范例:测试程序 —— Test.java
• 测试的过程中所有的bean的实例都要求从Spring的配置文件中找到。
package org.lxh.simple.test;
import org.lxh.simple.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
Hello hello = (Hello)ctx.getBean("hellolower") ;
System.out.println(hello.sayHello());
}
}
以上的代码已经可以得到一个子类的实例,与之前的工厂设计相比,有如下的好处:
• 程序不用再处理工厂的实例化
• 程序以接口为标准
• 程序中通过key,可以找到一个具体的value。
如果要修改使用的子类,直接修改applicationContext.xml文件即可,而不用再去修改任何的程序代码,便于程序的变更。
实际上Spring就相当于是一个大的工厂。
那么除此之外Spring还有那些好处呢?直接修改实现类:将实现类变为一个:
package org.lxh.simple.impl;
import org.lxh.simple.Hello;
public class HelloImpl implements Hello {
private String info ;
public String sayHello() {
return this.getInfo();
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
此实现类中存在了一个info属性,也同时存在了setter及getter方法,此时info的内容可以直接通过配置文件设置到类之中。
<bean id="helloimpl"
class="org.lxh.simple.impl.HelloImpl"
parent="hello">
<property name="info">
<value>helloworld!!!</value>
</property>
</bean>
在配置文件之中,<bean>的节点下增加了<property>节点,表示要为bean中的属性赋值,内容为helloworld!!,以后如果在程序中直接使用了helloimpl实例化Hello接口的话,会自动把内容设置到HelloImpl类中的info属性之中。
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
Hello hello = (Hello)ctx.getBean("helloimpl") ;
System.out.println(hello.sayHello());
}
}
从以上的代码中可以发现,Spring完全是由配置文件决定效果的,所有的关系、属性的内容都可以通过Spring的配置文件指定,实际上这就是Spring中对于Ioc(控制反转)的支持
3.2、IOC的作用
之前的代码是使用了依赖注入的方式把内容设置到Bean类之中,实际上在Spring中依赖注入可以有多种形式,例如,可以在构造方法上传递所需要的内容。
例如:现在有如下的一个类
public class Person {
private String name ;
private int age ;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age ;
}
}
在此类中没有无参构造方法,之后可以直接通过applicationContext进行配置。
applicationContext.xml:
<bean id="per1" class="org.lxh.ioc.demo01.Person">
<constructor-arg index="0">  构造方法的参数,index表示参数的位置
<value>zhangsan</value>  表示参数的内容
</constructor-arg>  第二个参数
<constructor-arg index="1">
<value>30</value>  是一个数字,所以直接写上数字
</constructor-arg>
</bean>
验证:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
System.out.println(ctx.getBean("per1"));
}
}
除了以上的注入方式外,还可以指定一个bean的实例注入进去。
例如:在配置文件之中声明一个java.util.Date的对象。
<bean id="date" class="java.util.Date"></bean>
之后声明一个包含了date属性的POJO类。
Person.java:
package org.lxh.ioc.demo02;
import java.util.Date;
public class Person {
private String name ;
private int age ;
private Date birthday ;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age + "生日:" + this.birthday ;
}}
把之前配置的date对象设置到Person类之中。
<bean id="per2" class="org.lxh.ioc.demo02.Person">
<constructor-arg index="0">
<value>zhangsan</value>
</constructor-arg>
<constructor-arg index="1">
<value>30</value>
</constructor-arg>
<property name="birthday">
<ref bean="date"></ref>  表示使用本配置文件之中配置好的date实例
</property>
</bean>
测试:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
System.out.println(ctx.getBean("per2"));
}
}
那么,此时,实际上就可以利用此种概念,注入更加复杂的类型,例如:自定义两个类,之后在配置文件中建立关系。
例如:一个人有一本书
Person.java:
package org.lxh.ioc.demo03;
public class Person {
private String name ;
private int age ;
private Book book ;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age ;
}
}
Book.java:
package org.lxh.ioc.demo03;
public class Book {
private String title ;
private float price ;
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
在配置文件中配置出此种关系
<bean id="book3" class="org.lxh.ioc.demo03.Book">
<property name="title">
<value>JAVA</value>
</property>
<property name="price">
<value>99.9</value>
</property>
</bean>
<bean id="per3" class="org.lxh.ioc.demo03.Person">
<property name="name">
<value>zhangsan</value>
</property>
<property name="age">
<value>30</value>
</property>
<property name="book">
<ref bean="book3"></ref>
</property>
</bean>
在此配置文件之中完全的将两个类的关系进行合理的配置,直接从配置文件之中就可以发现之间的联系。
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
Person per = (Person)ctx.getBean("per3") ;
System.out.println(per.getBook().getTitle());
}
}
在IOC中还有一种技术称为自动绑定,可以自动绑定所需要的类型的对象,有byType、byName方式。
1、 使用类型进行自动绑定
package org.lxh.ioc.demo04;
import java.util.Date;
public class Person {
private String name ;
private int age ;
private Date birthday ;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age + ";生日:" + this.birthday ;
}
}
将配置好的Date的实例通过类型自动设置进去
<bean id="per4" class="org.lxh.ioc.demo04.Person" autowire="byType">
<property name="name">
<value>zhangsan</value>
</property>
<property name="age">
<value>30</value>
</property>
</bean>
测试:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
System.out.println(ctx.getBean("per4"));
}
}
通过类型自动把内容设置进去了,自动注入。
2、 通过名称注入
<bean id="birthday" class="java.util.Date"></bean>
<bean id="per5" class="org.lxh.ioc.demo05.Person" autowire="byName">
<property name="name">
<value>zhangsan</value>
</property>
<property name="age">
<value>30</value>
</property>
</bean>
可以发现,在定义date类型的时候,名称与Person类中的Date属性名称一致,此时直接使用byName绑定。
以上的两种比较常用,如果需要的话,还可以直接在构造方法上进行自动的绑定操作。
例如:有如下的类
import java.util.Date;
public class Person {
private Date birthday ;
public Date getBirthday() {
return birthday;
}
public Person(Date birthday) {
super();
this.birthday = birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String toString(){
return "生日:" + this.birthday ;
}
}
在以上的类中,是通过构造方法进行内容的设置,配置如下:
<bean id="per6" class="org.lxh.ioc.demo06.Person"
autowire="constructor">
</bean>
使用IOC可以注入更加复杂的内容,例如:对象数组、List、Set、Map类型的数据
1、 对于注入对象数组和List实际上配置文件没有太大的区别,是一样的,只是内部接收的方式不一样。
建立一个Person的POJO类,同时在建立一个书的类,一个人有多本书。此时注入的是一组对象,可以使用对象数组或是List进行接收。
Book.java:
public class Book {
private String title ;
private float price ;
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
建立Person的类,Person类中包含多个Book对象。
Person.java:
public class Person {
private String name ;
private int age ;
private Book[] books ;
public Book[] getBooks() {
return books;
}
public void setBooks(Book[] books) {
this.books = books;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age ;
}
}
Person类中存在了一个书的对象数组,此时,通过配置文件进行关系的配置。
<bean id="book1" class="org.lxh.ioc.demo07.Book">
<property name="title">
<value>JAVA</value>
</property>
<property name="price">
<value>100</value>
</property>
</bean>
<bean id="book2" class="org.lxh.ioc.demo07.Book">
<property name="title">
<value>Oracle</value>
</property>
<property name="price">
<value>111</value>
</property>
</bean>
<bean id="book3" class="org.lxh.ioc.demo07.Book">
<property name="title">
<value>JSP</value>
</property>
<property name="price">
<value>122</value>
</property>
</bean>
<bean id="per7" class="org.lxh.ioc.demo07.Person">
<property name="name">
<value>zhangsan</value>
</property>
<property name="age">
<value>30</value>
</property>
<property name="books">
<list>
<ref bean="book1"/>
<ref bean="book2"/>
<ref bean="book3"/>
</list>
</property>
</bean>
测试:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
Person per = (Person)ctx.getBean("per7") ;
System.out.println(per) ;
Book b[] = per.getBooks() ;
for(int i=0;i<b.length;i++){
System.out.println("\t|- " + b[i].getTitle());
}
}
}
此时,可以直接把类中的对象数组修改为List集合,两者的运行效果是完全一样的。
Person.java:
package org.lxh.ioc.demo08;
import java.util.List;
public class Person {
private String name ;
private int age ;
private List books ;
public List getBooks() {
return books;
}
public void setBooks(List books) {
this.books = books;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age ;
}
}
配置文件不需要做任何的修改,因为在配置的时候本身使用的就是<list>节点。测试:
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = null ;
// 表示找到配置文件
ctx = new ClassPathXmlApplicationContext("applicationContext.xml") ;
// 从配置文件之中取得Bean的实例
Person per = (Person)ctx.getBean("per8") ;
System.out.println(per) ;
Iterator iter = per.getBooks().iterator() ;
while(iter.hasNext()){
Book b = (Book)iter.next() ;
System.out.println("\t|- " + b.getTitle());
}
}
}
也可以直接使用Set节点进行注入。
<property name="books">
<set>
<ref bean="book1"/>
<ref bean="book2"/>
<ref bean="book3"/>
</set>
</property>
还可以把内容作为Map注入进来。
package org.lxh.ioc.demo09;
import java.util.Map;
public class Person {
private String name ;
private int age ;
private Map books ;
public Map getBooks() {
return books;
}
public void setBooks(Map books) {
this.books = books;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age ;
}
}
之后在配置文件中,必须同时设置好key与value。
<bean id="per9" class="org.lxh.ioc.demo09.Person">
<property name="name">
<value>zhangsan</value>
</property>
<property name="age">
<value>30</value>
</property>
<property name="books">
<map>
<entry key="book1">
<ref bean="book1"/>
</entry>
<entry key="book2">
<ref bean="book2"/>
</entry>
<entry key="book3">
<ref bean="book3"/>
</entry>
</map>
</property>
</bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值