学习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————————————————————




代理模式


代理类涉及几种类的类型

委托类(服务类)  提供核心服务

代理类   增强功能   访问控制   拦截过滤   延迟加载

客户类    调用核心服务的客户代码


代理的原则:1.代理类(中介)和委托类(房东)行为相似。代码上的体现就是实现了同一个接口

2.代理类增强了委托类的功能(中介帮房东把房价抬高了)



静态代理代码实现

代理模式就是在你想要的类里,加上另外的功能类,只需要把这个功能类,new出来,然后一层层嵌套就OK了

客户类只管拿,它拿到的不过是增强的类:类1(类2(类3))


代码

1.com.bjsxt.dao.impl 包下有实现类UserDaoImplForMysql.java、UserDaoImplForLog.java、UserDaoFactory.java、UserDaoImplForPower.java(UserDao接口只有一个add方法)


2.UserDaoImplForMysql类

public class UserDaoImplForMysql implements UserDao {

public void add( ){

System.out.println("mysql...add...User");

}

}


3.public class UserDaoImplForLog implements UserDao{

private UserDao userDao;
public UserDaoImpl4Log(UserDao userDao){
super();
this.userDao = userDao;
}
public void add() {
userDao.add();
System.out.println("UserDaoImpl4Log.add(日志打印,PM15:00 用户小高登录系统,添加了一条记录。。。)");
}
 

}

//嵌套委托类时要注意,要写带参构造而且,传入的参数要为UserDao


4.public class UserDaoImplForPower implements UserDao{

private UserDao userDao;


public UserDaoImplForPower(UserDao userDao){//这个类的有参构造,为什么需要这个有参构造呢?因为UserDaoFactory中代理类UserDaoImplForPower()这个方法里嵌套了多个委托类,委托类就是参数,而这个参数都实现了UserDao,再嵌套一个,它的接口还是UserDao,只是嵌套时写的是实现类。

super();

this.userDao = userDao;


public void add(){

userDao.add();      //通过它来调用实现了同一个UserDao接口的,被一串串嵌套的委托类,它调用的是一串委托类的每个add方法

System.out.println("权限判断。。。。");

}

}


5.public class UserDaoFactory{

public static UserDao getInstance( ){

Properties pp = new Properties( );

try{

pp.load(UserDao.class.getClassLoader( ).getResourceAsStream("db.properties"));    //这里是工厂和代理的结合,从db.properties中取出数据

}catch(IOException e){

e.printStackTrace( );

}

String dbtype = pp.getProperty("dbtype");

if("mysql".equals(dbtype)){

return new UserDaoImplForPower( new UserDaoImplForLog( new UserDaoImplForMysql()));       //这就是代理,代理类包装委托类,一层层套

}else if("oracle".equals(dbtype)){

return new UserDaoImplForOracle( );          //这是和工厂结合着使用,上面实现代理,除此之外,别的类还怎么执行就怎么执行

}else {

return null;

}

}

}

——————题外 怎么从db.properties中取到key的值——————

JDK提供了相关的类

Properties pp = new Properties();

pp.load(UserDaoFactory.class.getClassLoader().getResourceAsStream("db.properties"));

String dbtype = pp.getProperty("dbtype");

然后就直接使用dbtype吧

*db.properties中这样写:name=dbtype    value=mysql,想要改成oracle,去改写value的值


——————题外end————————————————————


6.写action层代码,开始测试(这堆被嵌套的代理类,应该提供一个让外界访问的入口,如action要调用,代码如下)

public class UserAction{

private UserDao userDao = UserDaoFactory.getInstance( );

public String add( ){

userDao.add( );     //调用方法开始,调到代理最外面那层时,它那还会另行调用一个add,以激活委托类的add

return null;

}

public UserDao getUserDao( ){   //userDao的get方法

return userDao;

}

public void setUserDao(UserDao userDao){//userDao的set方法

this.userDao = userDao;

}

public static void main(String[ ] args){

UserAction action = new UserAction( );

action.add( );

}

}


————静态代理end————————————————






—————题外 模式总结———————————

类还是那几个类,组合方式却不同了。就像带兵打仗,遇到不同的敌人,要改变不同的战术。

和敌人打海战,我用我的海军A Impl,和敌人打陆战,我用我的陆军A Impl2,这是工厂模式。

又比如一群人和反派大BOSS打架,打不过。。众人C和B就把武功都传给A,让A变得最强,来和BOSS打。这是代理模式。

学习Spring笔记一_第1张图片

————题外end——————————————————


你可能感兴趣的:(Spring框架)