学习Spring札记一
Spring有规划作用,耦合度低、更容易测试、代码更清晰简单。没有Spring也能写项目,但是用了Spring项目会更加‘健康’。Spring官方言,只要你用的是Java语言,就能用Spring,可见Spring对于Java有多重要,和数据库一样重要。用了Spring的Java项目都会更加健壮。Spring致力于J2EE应用的各层解决方案(企业管理软件开发),它现在是大多数企业开发的一站式选择。除此之外Spring可以和已有框架无缝整合,充分为开发人员考虑,如果你想用别的框架就用,不想用可以用Spring提供的服务,Spring的社区非常强大。
Spring的核心就两个IOC和AOP,但Spring中包含很多优秀的设计模式,你在使用它的时候已经在提高自己了。
优势:提供了IOC容器、AOP、提供简易的服务抽象(把底层的技术进行了简单的封装,让其更好用,如JDBC)、集成管理各种框架
作为铺垫我们要先学设计模式,Spring涉及了以下设计模式
单例模式——>工厂模式——>IOC——>代理(静态代理、动态代理——动态代理的进阶是AOP)
这几个模式按顺序来学
一
单例模式
常用的有四种创建方式:lazy、eager、static、享元
单例的原则是:1.自己创建自己 2.私有化构造器 3.提供对外的访问方法
经典的单例有
Servlet是单例,被所有线程共享
Session也是单例,在一次会话中只有一个Session,它的单例不彻底,只限于当前会话,这次会话的东西只能这次会话中取出来,数据在下次会话就消失了
Application是最彻底的单例,放进去的数据,会一直在,直到服务器被重启。
lazy懒汉式单例
用的时候再实例化,节省了内存空间
public class LazySingleton{ private static LazySingleton lazySingleton = null; private LazySingleton(){ super(); } public static synchronized LazySingleton getInstance(){ if(lazySingleton == null){ lazySingleton = new LazySingleton(); } return lazySingleton; } } |
*synchronized 为防止多个线程同时进入这个方法对此类进行实例化,使用了synchronized ,这样的缺点是每次有多个线程执行这个方法,都会排除等待,影响性能,除了第一次实例化后,就不需要再创建这个实例了,之后的访问也就不需要再上同步锁。理想的状态是:第一次访问时用同步锁,创建好这个实例后,以后再访问此方法就是去取创建好的实例,这时不需要有synchronized ,这样多个线程能同时访问此方法,性能会高很多。 synchronized一定要加哦!
eager饿汉式单例
不管用不用都会创建,相比之下更占用空间
public class EagerSingleton{ private static EagerSingleton eagerSingleton = new EagerSingleton(); private EagerSingleton(){ super(); } public static EagerSingleton getInstance(){ return eagerSingleton; } } |
static静态内部类式
它解决了Lazy的同步锁性能差问题,算是对Lazy的一种改进
public class StaticSingleton{ private StaticSingleton(){ super(); } private static class Temp{ //静态内部类 public static StaticSingleton ss = new StaticSingleton(); } public static StaticSingleton getInstance(){ return Temp.ss; } } |
1.用时再加载,有懒加载的特性,不访问getInstance就不会访问Temp.ss,就不会创建实例
2.安全不影响性能,实例是静态变量,Java语法设定了静态变量只能初始化一次,所以不用担心多个线程同时创建实例,不需要加synchronized。那这之后的访问,不论多少个线程,都不会排队等待,提高了性能。
托管式(享元式)单例
像之前的daoFactory,提供一个容器,把对象都放在这里面new,用的时候从里面拿。
总结单例:虽然简单,但是有讲究,不同的人有不同的思维方式。用哪种方式实现单例,取决于你。
从数量上讨论这个类是什么类
a.想让这个类只有一个对象(单例类)
b.想让这个类有若干(10个或100个)对象 —— 想让这个类有若干个固定数量的对象,一般用在对稀有资源的控制,我们把这种称为“池”,如数据库连接池,线程池
c.或是任意个对象(就是普通类,可以随便new)
什么样的类应该被设计成单例?
服务类(无状态)类应被设计成单例:只需要提供对外的服务,不提供数据存储,如servlet、dao
数据类(有状态)类不应被设计成单例:数据会变,不能设计成单例。因为它的数据会变,需要不止一次的实例化,如struts2的action,和po
有状态类——>有成员变量,而且成员变量是可变的,如Strtus2的action
无状态类——>类里没有成员变量,或者成员变量是不可变的,或是单例的,如struts1的action,因为它是无状态的。
单例模式的作用
1.控制资源的使用,通过线程同步来控制资源的并发访问
2.控制实例产生的数量,起到节约资源的目的
3.作为通信媒介使用,也就是数据共享,两个线程通信,从同一个实例中取数据。
数据库就是一个单例,一个线程把数据放到数据库中,另一个线程从数据库中取出来,数据放到同一个类里,才能达到数据传输的目的
————————题外——good answer——————
JSP四大作用域
page 当前页面,也就是只要跳到别的页面就失效了
request 一次请求,简单的理解就是一次请求范围内有效
session 一次会话,只要当前页面没有被关闭(没有被程序强制清除),不管怎么跳转都是有效的(比如360浏览器,你清除此页后,访问记录只是被标记为删除,你点击还能访问,除非你把浏览器关了)
application 服务器,只要服务器没有重启(没有被程序强制清除),数据就有效
JSP九大内置对象 对应servlet中的java对象
page this
pageContext PageContext
request HttpServletRequest
response HttpServletResponse
config ServletConfig
exception Throwable
out JspWrite
session HttpSession
application ServletContext
单例end————————————————————————————————
工厂模式
为什么要有工厂模式
当系统扩展需要添加新的产品对象时,使用工厂模式的项目仅仅需要添加一个具体对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放—封闭”原则。代码实现上是把new的过程放在一个类里,通过增加判断的结点来实现。
工厂模式分
1.简单工厂模式 一个对象,比如以前的dbutil
2.*工厂方法模式 一系列对象,比如下面的例子,可以根据需要换实现方法
3.抽象方法模式 高大神说比较复杂,挺少有人这么用
实例
1.创建两个包action、dao
2.dao包下创建接口UserDao,接口内容如下
public interface UserDao{
void add();
}
3.创建dao.impl包,并在包下创建接口的实现类UserDaoImpl4MySql,实现类内容如下
pulic class UserDaoImpl4MySql implements UserDao{
public void add(){
System.out.println(" I'M MySQL");
}
}
4.在dao.impl包下创建UserDaoImpl4Oracle类,并实现UserDao接口
public class UserDaoImpl4Oracle implements UserDao{
public void add(){
System.out.println("I',M Oracle");
}
}
//3和4的实现类实现同一个接口UserDao,意味着可以根据需要替换实现类
5.在dao.impl包下,创建一个UserDaoFactory类来封装所有实现类,内容如下
public class UserDaoFactory{
public static UserDao getInstance(){
String dbtype = "mysql"; //模拟从db.properties取出,实际应该是从db.properties中读取出dbtype
if("mysql".equals(dbtype)){
return new UserDaoImpl4Mysql();
}else if("oracle".equals(dbtype)){
return new UserDaoImpl4Oracle();
}else {
return null;
}
}
}
6.在action下创建UserAction类进行测试工厂方法是否可以“热插拨”变更实现类,代码如下
public class UserAction{
private UserDao userDao = UserDaoFactory.getInstance(); //父类引用指向子类方法,想换实现类时,只要把这里改了,这个步骤后续还会把它另外拿出来,放在spring的IOC容器中
public String add(){
userDao.add();
return null;
}
public static void main(String[ ] args){
UserAction userAction = new UserAction();
userAction.add();
}
}
//接下来运行UserAction,测试UserDao接口的实现类是否通过工厂方法模式实现了自由替换。
工厂模式end————————————————————