据度娘所载:
Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。
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/EEfull-stack(一站式)轻量级开源框架。
为什么说Spring是一个一站式的轻量级开源框架呢?EE开发可分成三层架构,针对JavaEE的三层结构,每一层Spring都提供了不同的解决技术。
从上面的简要介绍中,我们要知道Spring的核心有两部分:
我这儿使用的Spring的版本是spring-framework-4.2.4.RELEASE。
IOC:Inversion of Control,控制反转。指的是对象的创建权反转(交给)给Spring,其作用是实现了程序的解耦合。也可这样解释:获取对象的方式变了。对象创建的控制权不是“使用者”,而是“框架”或者“容器”。
用更通俗的话来说,IOC就是指对象的创建,并不是在代码中用new操作new出来的,而是通过Spring进行配置创建的。其底层实现原理是XML配置文件+SAX解析+工厂设计模式。
就拿持久层(也即dao(data access object,数据访问对象)层)的开发来说,官方推荐做法是先创建一个接口,然后再创建接口对应的实现类。
先创建一个Userdao接口
public interface UserDao {
public void add();
}
再创建Userdao接口的UserDaoImpl实现类
public class UserDaoImpl implements UserDao {
public void add() {
balabala......
}
}
接着我们在service层调用dao层,核心代码如下:
// 接口 实例变量 = new 实现类
UserDao dao = new UserDaoImpl();
dao.add();
可发现缺点:service层和dao层耦合度太高了。解决方法是使用工厂模式进行解耦合操作。
创建一个工厂类,在工厂类中提供一个方法,返回实现类的对象。
public class Factory {
// 提供返回实现类对象的方法
public static UserDao getUserDaoImpl() {
return new UserDaoImpl();
}
}
然后在service层调用dao层的核心代码就变为:
UserDao dao = Factory.getUserDaoImpl();
dao.add();
如若这样做,会发现又产生了一个缺点:service层和工厂类又耦合了。所以使用工厂模式进行解耦合也只是一种权宜之计。下面我就来简单讲讲Spring IOC的底层实现原理:
配置文件中可能会有如下配置信息:
id="userDaoImpl" class="cn.itcast.dao.impl.UserDaoImpl" />
也是要创建一个工厂类,在工厂类中提供一个返回实现类对象的方法,但并不是直接new实现类,而是使用SAX解析配置文件,根据标签bean中的id属性值得到对应的class属性值,使用反射创建实现类对象。
public class Factory {
public static UserDao getUserDaoImpl() {
// 1.使用SAX解析得到配置文件内容
// 直接根据id值userDaoImpl得到class属性值
String classvalue = "class属性值";
// 2.使用反射得到对象
Class clazz = Class.forName(classvalue);
UserDaoImpl userDaoImpl = (UserDaoImpl)lazz.newInstance();
return userDaoImpl;
}
}
这里我稍微讲一下面向对象设计的七大原则,不必强记,重在理解。
Spring的官网是http://spring.io。Spring的开发包的下载地址是
从下图可知:
由于我们只是初次入门Spring,所以也只是使用Spring的基本功能,所以需要使用到下面的这4个Jar包:
除此之外,还要导入Spring支持的日志Jar包:
在src目录下创建一个cn.itcast.ioc包,并在该包下创建一个User类。
public class User {
public void add() {
System.out.println("add.................");
}
}
注意:Spring配置文件的名称和位置没有固定要求,一般建议把该文件放到src下面,名称可随便写,官方建议写成applicationContext.xml。但我觉得这个文件名称太长了,所以决定写为bean1.xml。然后我们还需要在配置文件中引入约束,Spring学习阶段的约束是schema约束。那么问题来了,这个约束又该怎么写呢?可参考docs\spring-framework-reference\html
目录下的xsd-configuration.html文件,在其内容最后找到如下内容:
<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="foo" class="x.y.Foo">
<meta key="cacheName" value="foo"/>
<property name="name" value="Rick"/>
bean>
beans>
然后将其复制黏贴到配置文件bean1.xml中,将其修改为:
<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">
beans>
<bean id="user" class="cn.itcast.ioc.User">bean>
我们要在Spring中写代码来实现获取bean1.xml文件中配置的对象(该段代码不要求重点掌握,只是用在测试中而已)。这段代码主要用来解析Spring配置文件得到对象,但这个过程不需要我们写代码实现,Spring封装了一个对象帮我们进行了这些操作,这个对象叫ApplicationContext,它就能实现这个功能。
在cn.itcast.ioc包下创建一个TestIOC单元测试类,如下:
public class TestIOC {
// 得到配置的user对象
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml"); // classpath:类路径,src目录下的文件最终要编译到类路径下
// 2.根据配置文件的id得到user对象
User user = (User) context.getBean("user");
System.out.println(user);
user.add();
}
}
注意:classpath为类路径,src目录下的文件最终要编译到类路径下。
通俗一点说,Spring的bean管理即指创建对象时不需要new操作代码实现,而是交给Spring进行配置完成。
Spring进行bean管理有两种方式:
本文将重点放在第一种方式上,后一种方式后面会讲。
创建对象时候,调用类里面的无参数的构造方法实现。那么Spring配置文件中又该怎样写呢?基本类似于如下写法:
<bean id="user" class="cn.itcast.ioc.User">bean>
创建一个工厂类,在工厂类中提供一个静态的方法,这个方法返回类的对象;调用工厂类的方法时候,直接使用类名.方法名称
即可以调用。下面举例来说明。
在src目录下创建一个cn.itcast.bean包,并在该包下创建一个Bean1类。
public class Bean1 {
public void bean1() {
System.out.println("bean1..........");
}
}
然后在该包下创建一个Bean1Factory工厂类。
public class Bean1Factory {
// 静态方法
public static Bean1 getBean1() {
return new Bean1();
}
}
接着Spring配置文件中应向下面这样配置:
<bean id="bean1" class="cn.itcast.bean.Bean1Factory" factory-method="getBean1">bean>
最后在该包下创建一个TestIOC单元测试类。
public class TestIOC {
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.根据配置文件的id得到user对象
Bean1 bean1 = (Bean1) context.getBean("bean1");
System.out.println(bean1);
}
}
创建一个工厂类,在工厂类里面提供一个普通的方法,这个方法返回类对象;调用工厂类的方法时候,创建工厂类对象,使用对象调用方法即可。下面也举例来说明。
在src目录下的cn.itcast.bean包下创建一个Bean2类。
public class Bean2 {
public void bean2() {
System.out.println("bean2..........");
}
}
然后在该包下创建一个Bean2Factory工厂类。
public class Bean2Factory {
public Bean2 getBean2() {
return new Bean2();
}
}
接着Spring配置文件中应向下面这样配置:
<bean id="bean2Factory" class="cn.itcast.bean.Bean2Factory">bean>
<bean id="bean2" factory-bean="bean2Factory" factory-method="getBean2">bean>
最后将TestIOC单元测试类的代码修改为:
public class TestIOC {
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.根据配置文件的id得到user对象
Bean2 bean2 = (Bean2) context.getBean("bean2");
System.out.println(bean2);
}
}
Spring配置文件中bean标签常用的属性有以下四种:
scope属性:bean的作用范围。
scope属性共有以下5个属性:
singleton:创建的对象是单例的,也是scope属性的默认值。
下面我来举例说明它。将TestIOC单元测试类的代码修改为:
public class TestIOC {
// 得到配置的user对象
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.根据配置文件的id得到user对象
User user1 = (User) context.getBean("user");
User user2 = (User) context.getBean("user");
System.out.println(user1);
System.out.println(user2);
}
}
单元测试以上方法,一切就尽在不言中。其实,此时Spring配置文件中有关如下bean的配置:
<bean id="user" class="cn.itcast.ioc.User">bean>
就相当于:
<bean id="user" class="cn.itcast.ioc.User" scope="singleton">bean>
prototype:创建的对象是多实例的。
也可举例来说明它。将Spring配置文件中有关如下bean的配置:
<bean id="user" class="cn.itcast.ioc.User">bean>
修改为:
<bean id="user" class="cn.itcast.ioc.User" scope="prototype">bean>
测试单元测试类的方法就能明白了。
通过配置
标签上的init-method作为bean的初始化的时候执行的方法,配置destroy-method作为bean的销毁的时候执行的方法。销毁方法想要执行,需要是单例创建的Bean而且在工厂关闭的时候,Bean才会被销毁。
实际上,有关Bean的属性注入共有三种方式,下面我分别加以简单的说明:
set方法注入
用代码可表示如下:
public class Book {
private String bookname;
public void setBookname(String bookname) {
this.bookname = bookname;
}
}
Book book = new Book();
book.setBookName("Java编程思想");
有参数构造注入
用代码可表示如下:
public class Book {
private String bookname;
public Book(String bookname) {
this.bookname = bookname;
}
}
Book book = new Book("代码大全");
接口注入
先编写一个接口:
public interface Dao {
public void add(String name);
}
public class DaoImpl implements Dao {
private String name;
public void add(String name) {
this.name = name;
}
}
但在Spring框架里面,只支持前两种方式,即set方法注入和有参数构造注入。下面我来举例分别演示。
在src目录下创建一个cn.itcast.property包,并在该包下编写一个Book实体类。
public class Book {
private String bookname;
public Book(String bookname) {
this.bookname = bookname;
}
public void testBook() {
System.out.println("book.............." + bookname);
}
}
接着在Spring配置文件中对以上JavaBean添加如下配置:
<bean id="book" class="cn.itcast.property.Book">
<constructor-arg name="bookname" value="beautifulMan
美美侠">constructor-arg>
bean>
最后在该包下编写一个TestIOC单元测试类:
public class TestIOC {
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Book book = (Book) context.getBean("book");
book.testBook();
}
}
自己自行测试去吧!
我们同样在cn.itcast.property包下编写一个Person实体类,在类中定义属性,并生成set方法。
public class Person {
// 1.定义一个属性
private String username;
// 2.生成这个属性的set方法
public void setUsername(String username) {
this.username = username;
}
public void testperson() {
System.out.println("person.............." + username);
}
}
然后在Spring配置文件中,使用bean标签创建对象,在bean标签里面使用property标签注入属性。即在Spring配置文件中对以上JavaBean添加如下配置,
<bean id="person" class="cn.itcast.property.Person">
<property name="username" value="李阿昀">property>
bean>
最后将TestIOC单元测试类的代码修改为:
public class TestIOC {
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Person person = (Person)context.getBean("person");
person.testperson();
}
}
自己自行测试去吧!
在实际开发中,我们要提交表单到action里面去,然后在action里面调用service层的方法,接着在service层里面调用dao层的方法。在这里,我假设在service层里面调用dao层的方法,所以需要在servcie层里面创建dao层的对象实现调用。
先在src目录下创建一个cn.itcast.dao包,并在该包下编写一个UserDao类。
public class UserDao {
public void add() {
System.out.println("dao................");
}
}
然后在src目录下再创建一个cn.itcast.service包,并在该包下编写一个UserService类。
public class UserService {
public void add() {
System.out.println("service.........");
// 调用dao
balabala......
}
}
如果我们使用最原始的方式在service层里面调用dao层的方法,那么UserService类中add()方法应这样写:
public void add() {
System.out.println("service.........");
// 原始方式,调用dao
UserDao dao = new UserDao();
dao.add();
}
在Spring里面,我们就应该这么玩了。我们的最终目的是在service层里面得到dao层对象。所以步骤为:
第一步,让dao作为service的一个属性。
// 1.让dao作为service的一个属性
private UserDao userDao;
第二步,生成dao属性的set方法。
// 2.生成dao属性的set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
这时,UserService类的代码就变成:
public class UserService {
// 1.让dao作为service的一个属性
private UserDao userDao;
// 2.生成dao属性的set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service.........");
userDao.add();
}
}
在Spring配置文件中进行配置和注入。
<bean id="userDao" class="cn.itcast.dao.UserDao">bean>
<bean id="userService" class="cn.itcast.service.UserService">
<property name="userDao" ref="userDao">property>
bean>
在src目录下创建一个cn.itcast.propertydemo包,并在该包下编写一个Orders实体类。
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
public void testorders() {
System.out.println("orders................" + oname);
}
}
xmlns:p="http://www.springframework.org/schema/p"
紧接着,我们需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders" p:oname="去你妈的!!!">bean>
public class TestIOC {
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Orders orders = (Orders)context.getBean("orders");
orders.testorders();
}
}
测试即可。
结论——使用p名称空间:
将cn.itcast.propertydemo包下的Orders类的代码修改为:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 1.数组类型的属性
private String[] arrays;
public void setArrays(String[] arrays) {
this.arrays = arrays;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("数组:" + Arrays.toString(arrays));
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders">
<property name="arrays">
<list>
<value>叶子value>
<value>liayunvalue>
<value>杰哥value>
list>
property>
bean>
最后将cn.itcast.property包下的TestIOC单元测试类的代码修改为:
public class TestIOC {
@Test
public void demo1() {
// 1.加载Spring配置文件,把配置文件中的对象进行创建
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Orders orders = (Orders)context.getBean("orders");
orders.testorders();
}
}
测试即可。
将cn.itcast.propertydemo包下的Orders类的代码修改为:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 2.list类型的属性
private List list;
public void setList(List list) {
this.list = list;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("list:" + list);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders">
<property name="list">
<list>
<value>叶子value>
<value>李昀玲value>
<value>杰哥value>
list>
property>
bean>
cn.itcast.property包下的TestIOC单元测试类的代码勿须修改,直接测试即可。
将cn.itcast.propertydemo包下的Orders类的代码修改为:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 3.set类型的属性
private Set keyset;
public void setKeyset(Set keyset) {
this.keyset = keyset;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("set:" + keyset);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders">
<property name="keyset">
<set>
<value>蝙蝠侠value>
<value>钢铁侠value>
<value>美美侠value>
set>
property>
bean>
其实,以上配置也可以写为:
<bean id="orders" class="cn.itcast.propertydemo.Orders">
<property name="keyset">
<list>
<value>蝙蝠侠value>
<value>钢铁侠value>
<value>美美侠value>
list>
property>
bean>
cn.itcast.property包下的TestIOC单元测试类的代码勿须修改,直接测试即可。
将cn.itcast.propertydemo包下的Orders类的代码修改为:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 4.map类型
private Map map;
public void setMap(Map map) {
this.map = map;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("map:" + map);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders">
<property name="map">
<map>
<entry key="username" value="潘金莲">entry>
<entry key="password" value="1314">entry>
<entry key="address" value="明初">entry>
map>
property>
bean>
cn.itcast.property包下的TestIOC单元测试类的代码勿须修改,直接测试即可。
将cn.itcast.propertydemo包下的Orders类的代码修改为:
public class Orders {
private String oname;
public void setOname(String oname) {
this.oname = oname;
}
// 5.properties
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void testorders() {
// System.out.println("orders................" + oname);
System.out.println("properties:" + properties);
}
}
然后需要在Spring核心配置文件中添加如下配置:
<bean id="orders" class="cn.itcast.propertydemo.Orders">
<property name="properties">
<props>
<prop key="name">宫本一郎prop>
<prop key="address">日本prop>
props>
property>
bean>
cn.itcast.property包下的TestIOC单元测试类的代码勿须修改,直接测试即可。
ApplicationContext接口有两个实现类,如下图:
下面应该是BeanFactory类的继承体系图吧!
稍微了解一下就好,这个类在实际开发中我们并不需要用到。
虽然使用这两个对象都可以加载Spring的配置文件,并创建配置文件中的对象。但他俩还是有区别的,最主要的区别是:
在实际的开发中,我们一般会使用SSH(即Struts2、Spring、Hibernate)进行开发,然后创建Spring的配置文件,使用applicationContext对象加载配置文件,继而创建对象。在真正的开发中,我们一般不会直接写applicationContext代码加载配置文件。
在服务器启动的时候,加载Spring配置文件,并创建对象。
Spring整合Web项目用到以下两个技术:
在服务器启动的时候,每个项目都会创建一个ServletContext对象,而且每个项目只有一个ServletContext对象。在ServletContext对象创建的时候,使用监听器可以监听到其创建。当我们监听到ServletContext对象创建时,Spring就会帮我们做一件事情——加载Spring配置文件,并把配置文件中的对象进行创建,对象创建之后,放到ServletContext域里面去,最终我们要使用创建的对象,可从ServletContext域里面获取出来。
Spring框架学习小结
利用周末加课设空余的时间认真学习了一下Spring框架,做个小结:
Spring框架的核心为IOC和AOP,IOC:控制反转,AOP:面向切面编程。优点:分层的一站式轻量级框架,具有简单、可测试、松耦合等特点。
底层原理:(1)xml配置文件
(2)dom4j解析xml文件
(3)工厂设计模式
(4)反射(主要):Class class=Class.forName(类路径)
类名 类对象=class.newInstance();
DI:依赖注入,含义与IOC相同。作用:在使用Spring框架创建对象时,动态地将其所依赖的对象注入Bean组件中。
实现方式:(1)setter方法注入,又分为调用无参构造器实例化Bean和无参静态工厂方法实例化Bean。
(2)构造方法注入:通过调用带参数的构造方法实现,每个参数代表一个依赖。
@Component(""),@Repository(""),@Service(""),@Controller("")注解功能相同,用作类对象的创建(Bean的装配)
@Resource(name=""):属性注入(基本类型或类对象)
使用注解装配需开启注解扫描:
\
———————————————————————————————————————————————AOP:面向切面编程,采用横向抽取机制。底层实现:动态代理
AspectJ:基于Java语言的AOP框架,提供了强大的AOP功能。
基于注解的声明式AspectJ:@Aspect:定义切面
@Pointcut:定义切入点表达式(表达式格式:execution( com.edu.sdju..(..)”)与com之间有一个空格)
@Before(“”):前置增强 @AfterReturning(“”):后置增强
@Around(“”):环绕通知 @AfterThrowing(value"",throwing=""):异常通知
@After(“”):最终通知
———————————————————————————————————————————————
针对数据库的操作,Spring提供了JdbcTemplate类
JdbcTemplate常用方法:(1)execute():完成执行SQL语句的功能
(2)update(String sql,Object... args):完成插入、更新、删除数据的操作,参数不能为NULL,返回受影响的行数
(3)query():
1)queryForObject(String sql,Class
例:String sql="select count(*) from user;
int count=jdbcTemplate.queryForObject(sql,Integer.class)
2)queryForObject(String sql,RowMapper rowMapper,Object... args):返回一个Object类型的单行记录
3)List query(String sql,RowMapper rowMapper):返回一个List类型的结果
—————————————————————————————————————————————————————
(1)什么是事务:用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位
(2)事务特性:原子性、一致性、隔离性、持续性(ACDI)
Spring事务管理提供接口PlatformTransactionManager:事务管理器
Spring事务管理的方式:(1)编程式事务管理
(2)声明式事务管理(xml,annotation)
基于Annotation方式的声明式事务
1.配置事务管理器(xml文件中配置)
2.开启注解扫描
3.注册事务注解驱动
4.在需要使用事务的SpringBean类或者Bean类的方法上添加注解@Transactional
OVER!