官网:https://spring.io/
框架(Framework):一系列的jar包,同时约定了实现某个功能的编程方式,可能与原有的编程方式并不相同!每个框架都解决了某些特定的问题!
Spring框架解决的问题:解决了创建和管理对象的问题,实现了解耦!
简单的创建对象的语法大致是:
User user = new User();
使用以上方式创建对象不便于实现解耦!
解耦:解除对象的之间的耦合!即降低对象之间的依赖关系!
依赖:在一个对象的工作过程中,需要使用到另一个对象,则称之为依赖另一个对象!
例如:
public class UserJdbcDao {
public void login() {
// 连接数据库
// 执行SQL语句
}
}
public class UserLoginServlet {
public UserJdbcDao userJdbcDao = new UserJdbcDao();
public void doPost() {
userDao.login();
}
}
在以上代码中,UserLoginServlet
就是依赖于UserJdbcDao
的!
在以上代码的基础之上,如果UserJdbcDao
使用的技术需要更换,或者出于其它的原因,这个类已经不再满足项目的需求,需要换成另一个类,或使用另一种技术来实现,则可能创建新的UserMyBatisDao
来替换原有的UserJdbcDao
!
如果需要替换,则以上代码中public UserJdbcDao userJdbcDao = new UserJdbcDao();
就需要被替换为:
public UserMyBatisDao userMyBatisDao = new UserMyBatisDao();
如果这个项目中,有多个Servlet
组件都使用了UserJdbcDao
,则需要替换多次!
所以,如果要把UserJdbcDao
替换为UserMyBatisDao
,整个项目中需要调整的代码可能较多!通常,就称之为“耦合度太高”!
首先,可以定义一个接口:
public interface UserDao {
void login();
}
然后,使得UserJdbcDao
和UserMyBatisDao
都实现以上接口!则后续需要使用DAO对象时,可以声明为:
// 使用接口声明,创建某个实现类的对象
public UserDao userDao = new UserJdbcDao();
则后续需要替换时,该对象的声明语句是不用调整的!
接下来,还可以使用设计模式中的工厂模式来解决创建对象的问题:
public class UserDaoFactory {
public static UserDao newInstance() {
return new UserJdbcDao();
}
}
则此前的代码可以进一步调整为:
public UserDao userDao = UserDaoFactory.newInstance();
在任何一个Servlet
中,需要使用DAO时,都使用以上代码即可,以上代码中根本就没有出现哪个实现类的名称,如果需要替换实现类,以上代码根本就不需要调整!需要调整的只有工厂类中的方法的返回值而已!
也可以看到,在Servlet
类中,根本就不需要出现某个DAO类的名称,则可以称之为UserLoginServlet不依赖于UserJdbcDao或UserMyBatisDao!也就解除了UserLoginServlet
和UserJdbcDao
或UserMyBatisDao
之间的耦合度!
在以上做法中,就使用到了接口、工厂类,它们是解耦的核心!但是,在实际开发某个项目时,不可能为大量的类都去创建对应的接口与工厂类!所以,就出现了Spring框架!可以简单的将Spring框架理解为一个大型工厂,专门用于创建和管理项目中所需的类的对象,当需要使用某个对象时,从Spring框架中获取即可,而不再是自行创建对象、自行编写工厂等!
首先,创建Maven Project,创建过程中,勾选Create a simple Project,Group Id填写cn.tedu
,Artifact Id填写Spring01
,Packaging选择war
。
如果仅仅只是使用Spring,以上Packaging并不需要选择
war
,选择jar
也是可以的!
创建的项目默认没有web.xml文件,需要先生成该文件,否则,项目会报错!
创建完成后,需要在pom.xml中添加org.springframework
的spring-webmvc
依赖:
org.springframework
spring-webmvc
4.3.8.RELEASE
如果只是使用Spring框架的内容,添加
spring-context
依赖即可,并不需要spring-webmvc
,由于后续将学习SpringMVC框架,在spring-webmvc
中包含了spring-context
,所以,也可以直接使用spring-webmvc
。
此次所添加的依赖只要是4.2或以上版本均可!可选版本有:4.3.14.3.10,4.3.124.3.14等。
然后,从http://doc.tedu.cn/config/spring-context.zip
下载Spring配置文件,解压后得到applicationContext.xml文件,将该文件复制到项目的src/main/resources下。
假设需要通过Spring创建Date
类的对象,则在applicationContext.xml中添加配置:
最后,创建可运行的类,添加代码:
ClassPathXmlApplicationContext ac
= new ClassPathXmlApplicationContext(
"applicationContext.xml");
Date date = (Date) ac.getBean("date");
System.out.println(date);
ac.close();
运行,即可看到输出的日期时间。
以上做法要求该类存在无参数构造方法!
某些类也许没有无参构造方法,但是,可能存在某个被static
修饰的方法,并且该方法就返回当前类型的对象,例如Calendar
类中就存在:
public static Calendar getInstance() { ...
以上getInstance()
方法就是Calendar
类的静态工厂方法!
如果需要使用Spring管理Calendar
的对象,则需要在applicationContext.xml中配置:
假设某个类并不满足以上2种方式创建对象,并且,存在另一个类,类中有某个方法可以创建对象,例如:
public class UserDao {
public UserDao(String s) {
}
}
public class UserDaoFactory {
public UserDao newInstance() {
return new UserDao(null);
}
}
则配置为:
由Spring管理的对象,默认都是单例的!
单例:在同一时间,某个类的对象一定只有1个!
如果需要配置对象是否单例,可以:
如果是自行设计单例模式,可以是例如:
public class User {
private static User user = new User();
private User() {
}
public static User getInstance() {
return user;
}
}
由于被获取的对象是使用了static
修饰的,所以,单例的类的对象,都是静态的,也就是具有常驻内存的特点!则单例的对象的作用域就是整个程序加载这个类开始,直至程序运行结束!而非单例的对象的作用域就是普通的变量的作用域!
另外,单例模式还区分为懒汉式单例和饿汉式单例,如果是懒汉式单例模式,只会在获取对象的前一刻才创建对象,如果是饿汉式单例模式时,则项目运行之初就已经创建了对象!
默认情况下,由Spring管理的单例的对象都是饿汉式的!可以在Spring的配置文件中添加配置:
注意:必须是单例模式的基础之上,再讨论是否懒加载的问题!
关于懒汉式单例的实现代码:
public class User {
private static User user;
private static final Object lock = new Object();
private User() {
}
public static User getInstance() {
if (user == null) {
sychronized(lock) {
if (user == null) {
user = new User();
}
}
}
return user;
}
}
对象的生命周期就是从创建到销毁的历程。
以Servlet
为例,从创建到销毁的过程中,还会执行init()
、service()
、destroy()
方法,其中,init()
方法是创建对象之后就会立即执行的初始化方法,并且,只会执行1次,而service()
方法是每次接收到请求后都会执行的方法,可能执行若干次,destroy()
方法是销毁对象的前一刻执行的方法,也只会执行1次!
在Java EE中的Servlet
组件是由容器(例如Tomcat)创建并管理的!作为程序员,必须知道哪些方法在什么时候被调用,才可以正确的重写这些方法,从而决定“什么时候应该做什么事情”!
当使用了Spring框架后,对象的管理权也是交给了框架的!为了保证在初始化时能定制所需要执行的任务,在销毁之前能释放资源等,也可以在类中声明对应的生命周期方法:
public class User {
public User() {
super();
System.out.println("创建User对象!");
}
public void onCreate() {
System.out.println("User.onCreate()");
}
public void onDestroy() {
System.out.println("User.onDestroy()");
}
}
在配置时,添加init-method
和destroy-method
属性的配置: