深入浅出Spring

来源:互联网 发布:淘宝首页客服模块 编辑:程序博客网 时间:2024/06/18 14:07
深入浅出Spring(一)Spring概述

       现在很多的企业级项目中基本上都会用到了Spring框架,那么为什么会出现Spring,Spring是什么?这次的博文我主要为大家简单介绍一下Spring。


Java EE优缺点

       我们都知道在2003年Spring兴起之前,企业普遍使用J2EE技术来开发企业级应用,为什么用J2EE呢?主要原因有以下几个:

1、Java本身的跨平台能力,可移植性强
2、J2EE服务器内置了大量的容器服务,比如事务服务、JNDI服务和连接池服务等等
3、程序员可以基于Java EE API进行企业开发并部署到应用中


       虽然J2EE有着上述优点,但利用J2EE开发有一个致命的缺陷,即研发困难,而且J2EE开发非常容易出问题,比如数据库连接泄露。而Spring的出现则解决了上述问题,至于如何解决,我们会在接下来的文章中深入解释。


Spring是什么

        什么是Spring呢?Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring使开发者能够编写更干净、更可管理、并且更易于测试的代码。关于Spring具体如何去实现的,这等到我们以后的教程,我会为大家详细分析。     


Spring优点

       简单了解Spring之后,我们看一下Spring的优点

1、方便解耦,简化开发。
2、AOP编程的支持。
3、声明式事务的支持。
4、方便程序的测试。。
5、方便集成各种优秀框架。

6、降低Java EE API的使用难度。

深入浅出Spring(二) IoC详解

       上次的博客深入浅出Spring(一)Spring概述中,我给大家简单介绍了一下Spring相关概念。重点是这么一句:Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。在这句话中重点有两个,一个是IoC,另一个是AOP。今天我们讲第一个IoC。

IoC概念

       控制反转(Inversion of Control)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题。 它还有一个名字叫做依赖注入(Dependency Injection)。IoC不是什么技术,它是一种设计模式。

 

实例演示

       为了更好的说明IoC,我为大家举一个简单的例子,如有这样一个描述:某公司新成立了一个项目组,项目组有若干成员和一个项目组长,项目组成立后第一次开会上,作为项目组长的小李按照惯例首先做了简短的自我介绍。

       根据上述的描述,如果我们写出如下代码和类图:

复制代码
    public class Li {            public void introduce() {            System.out.println("大家好,我是小李");        }    }    public class Team {        public void firstMeeting() {            Li li = new Li();            li.introduce();        }    }
复制代码
      具体类图如下:


       上述的代码,应该说基本完成了相关的需求,但是仔细考虑之后就会发现,上述的代码是根据具体的场景描述进行的,并没有进行抽象,这样就导致我们不能灵活的安排项目组长去做开场,即根据现在的代码,开场自我介绍被绑定给了小李而不能安排给其他人。为了解决上述的问题,我们引入首先引入Leader接口,相关代码和类图如下: 

复制代码
    public interface Leader {        public void introduce();    }    public class Li implements Leader {        @Override        public void introduce() {            System.out.println("大家好,我是小李");        }    }    public class Team {        public void firstMeeting() {            Leader li = new Li();            li.introduce();        }    }
复制代码

       具体类图如下:

        虽然上述的代码可以让我们安排给其他成员开场,但是我们可以看出Team类同时依赖Leader接口和Li类,并没有达到我们所期望的Team仅仅依赖于Leader接口的目的,如何解决这个问题呢?当然是引入Boss,由Boss决定具体由谁担任项目组长。具体类图和代码如下:

复制代码
    public interface Leader {        public void introduce();    }    public class Li implements Leader {        @Override        public void introduce() {            System.out.println("大家好,我是小李");        }    }        public class Team {        public void firstMetting(Leader leader){            leader.introduce();        }    }        public class Boss {        public void direct(){            Leader leader = new Li();            Team team = new Team();            team.firstMetting(leader);        }    }
复制代码

        具体类图如下:

        通过以上代码和图示,我们可以看出,通过引入老板类,我们将项目小组和具体由谁担任项目组长进行解耦

       对应上述例子,我们再来讲解一下IoC,IoC从字面上看分为控制和反转,控制在上面的实例中就是具体由谁担任项目组长,而反转就是将决定谁担任项目组长转移到Boss类中。通俗理解就是将接口的具体实现类(Li)的控制权从调用类(Team)中分离转交给第三方(Boss)决定。

深入浅出Spring(三) AOP详解

        上次的博文深入浅出Spring(二) IoC详解中,我为大家简单介绍了一下Spring框架核心内容中的IoC,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming),即面向切面编程。

1、OOP回顾

       在介绍AOP之前先来回顾一下大家都比较熟悉的OOP(Object Oriented Programming)。OOP主要是为了实现编程的重用性、灵活性和扩展性。它的几个特征分别是继承、封装、多态和抽象。OOP重点体现在编程架构,强调的是类之间的层次关系。

2、OOP缺陷

       为了更好的说明OOP的概念,我们接下来讲一个OOP的实例,重点分析OOP存在哪些缺陷,以便更好的理解AOP的相关内容。

       先看如下的一张图:

 

       上面这张图有三个类:Dog,Cat和Duck,他们都有一个方法run。按照OOP的设计理念,我们很容易就会想到抽象出一个Animal父类,同时让这三个子类继承Animal父类。这样的设计可以用如下的图示表示:

 

       在OOP思想中,我们会使用大量的类似上图的编程方式,对类进行抽象、继承、封装和多态来实现编程的重用性、灵活性和扩展性。但是这样的编程仍然有一定的局限性,有时候,OOP并不能很好解决我们再实际开发中遇到的问题。为了说明这个问题,看下面的图示:

 

       看到上面的图,我们暂时还不能发现有什么问题。为了大家便于理解,接下来我来给大家讲解一下上面类图的实现过程。描述如下:马戏团有一条表演的小狗,这条小狗可以跑和跳,但是它完成跑和跳两个动作之前必须是在接到驯兽师发出的命令后,同时完成跑和跳的动作之后,驯兽师会给与响应的奖励,比如一块肉。

       了解了实现过程之后,我们在来看一下具体的代码。 

复制代码
    public class Dog {           public void run() {            System.out.println("驯兽师发出命令!")            System.out.println("小狗开始跑!");            System.out.pringln("驯兽师给与奖励");        }          public void jump() {            System.out.println("驯兽师发出命令!")            System.out.println("小狗开始跳!");            System.out.pringln("驯兽师给与奖励");        }    }
复制代码
    仔细看上面的代码,我们可以看出在run方法和jump方法中,存在一些相同的内容(驯兽师发出命令和给与奖励),这些内容并不能完全进行抽象,即不能按照OOP编程思想进行处理。类似这样的情况同样会出现在我们编程中的很多地方,例如:日志记录、性能统计、安全控制、事务处理、异常处理等等。但是这样的情况该如何解决呢?这就引入了AOP编程思想。

 

3、AOP简介

       AOP为Aspect Oriented Programming的缩写,即面向切面编程(也叫面向方面),是一种可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

 

4、AOP实现实例

      为了大家更好的理解AOP如何实现,接下来我们优化一下上述代码。

      首先是Dog类

复制代码
    public interface Animal {        public void run();        public void jump();    }        public class Dog implements Animal{        public void run(){            System.out.println("小狗开始跑!");        }            public void jump(){            System.out.println("小狗开始跳!");        }            }
复制代码

     对比之前的代码我们可以明显看出,我们将关于驯兽师的相关内容从run和jump中进行了抽取,接下来,我们如何在程序运行中将关于驯兽师的动作加入到程序中呢?这就是我们这次用到的AOP实现的核心技术动态代理(Dynamic Proxy)。具体代码如下:

复制代码
    public class MyProxy  implements InvocationHandler{        private Object targetObject;                public Object createProxyInstance(Object targetObject) {            this.targetObject = targetObject;            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),                                    targetObject.getClass().getInterfaces(),                                    this);        }                public Object invoke(Object proxy, Method method, Object[] args)                throws Throwable {            command();                    Object ret = method.invoke(targetObject, args);            award();            return ret;        }                private void command() {            System.out.println("驯兽师发出命令!");        }                private void award(){            System.out.println("驯兽师给与奖励!");        }    }
复制代码
  上述代码实现完成之后,我们改如何调用呢?参考代码如下:
复制代码
    public class Client {        public static void main(String[] args) {            MyProxy hander = new MyProxy();            Animal dog = (Animal)hander.createProxyInstance(new Dog());            dog.run();            dog.jump();        }    }
复制代码
  执行结果如下:

 

       关于AOP编程的实例演示就完成了,接下来重新回顾一下AOP与OOP的相关概念。

 

5、AOP与OOP的关系

       OOP针对业务处理过程的实体(Dog、Cat、Duck)及其属性和行为(run)进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过程中(run或jump)的切面(command和award)进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

深入浅出Spring(四) Spring实例分析

       上次的博文中 深入浅出Spring(二) IoC详解 和 深入浅出Spring(三) AOP详解中,我们分别介绍了一下Spring框架的两个核心一个是IoC,一个是AOP。接下来我们来做一个Spring的实例。

       为了更好的讲解Spring的相关内容,这次的博文会针对一个【添加用户】的实例,进行逐步的解剖和优化,再此过程中,细节内容大家不需要考虑,只需要加深对Spring的理解即可。

 1、实例一

       首先,我们来看一个没有使用任何Spring框架内容,比较单纯的添加用户的实例。先看一下相关的类图和实现代码,具体如下:

复制代码
public class User {            private String username;        private String password;                public String getUsername() {            return username;        }        public void setUsername(String username) {            this.username = username;        }        public String getPassword() {            return password;        }        public void setPassword(String password) {            this.password = password;        }    }    public interface UserDao {        public void addUser(User user);    }    public class UserDao4OracleImpl implements UserDao {        @Override        public void addUser(User user) {                    System.out.println("UserDao4OracleImpl.addUser() , username="+user.getUsername());        }        }    public class UserDao4MySqlImpl implements UserDao {        @Override        public void addUser(User user) {                    System.out.println("UserDao4MySqlImpl.addUser()  , username="+user.getUsername());        }        }    public interface UserManager {            public void addUser(User user);    }    public class UserManagerImpl implements UserManager {        @Override        public void addUser(User user) {                    UserDao userDao = new UserDao4MySqlImpl();                    userDao.addUser(user);                }    }    public class Client {        public static void main(String[] args) {                        User user = new User();                    user.setUsername("张三");            user.setPassword("123456");                            UserManager userManager = new UserManagerImpl();                        userManager.addUser(user);                    }    }
复制代码

    分析上面的类图和代码中,我们可以很明显的看出:在UserManagerImpl类的方法addUser中,UserManagerImpl调用了UserDao及其具体的实现类UserDao4MySqlImpl,这就不符合IoC模式中,将接口的具体实现类的控制权从调用类中分离转交给第三方决定的相关思想,所以我们需要在这里进行修改。(参考我们之前的IoC文章)。

 

2、实例二

       针对实例一中不符合IoC思想的部分,我们进行相关修改,具体修改之后的相关类图和代码如下:

复制代码
    public class UserManagerImpl implements UserManager {        private UserDao userDao;         public UserManagerImpl (UserDao userDao){            this.UserDao = userDao;        }                @Override        public void addUser(User user) {                            this.userDao.addUser(user);                }    }        public class Client {        public static void main(String[] args) {                        User user = new User();                    user.setUsername("张三");            user.setPassword("123456");                            UserDao userDao =  new UserDao4MySqlImpl();                            UserManager userManager = new UserManagerImpl(userDao);                        userManager.addUser(user);                    }        }
复制代码

        分析上面修改之后的类图和代码,我们发现,虽然我们将UserDao的控制权交给了Client,但在Client中却存在对UserDao及其相关实现类的依赖,这样对于Client来讲,Client类与UserDao类之间的耦合性反而不如我们之前写的代码低。如何优化呢?我们这里就不做太多的思考,直接使用Spring的相关内容即可。

 

3、实例三

       对于实例二的问题,先来看一下我们使用Spring框架修改之后的相关类图,具体如下:

       看完上面类图之后,我们对比于第一张类图,可以看出:类与类之间的相互依赖更少,这样的结构能够使我们的代码耦合性更低。但这张类图的代码究竟是如何实现的呢?接下来,重点看一下我们需要修改的目标Client类的相关代码,具体如下:

复制代码
    public class Client {            public static void main(String[] args) {                        User user = new User();                    user.setUsername("张三");            user.setPassword("123456");                        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");            UserManager userManager = (UserManager)factory.getBean("userManager");                            userManager.addUser(user);                }    }
复制代码

    通过对比上面的代码和我们第二个实例中关于Client类的代码可以看出,上面的代码用到了一个BeanFactory类和XML文件,这就是Spring框架使用的核心类和实现方式。了解了两者的区别,我们再看一下XML文件中都写了什么,具体如下:

复制代码
    <?xml version="1.0" encoding="UTF-8"?>    <beans xmlns="http://www.springframework.org/schema/beans"             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"             xmlns:aop="http://www.springframework.org/schema/aop"             xmlns:tx="http://www.springframework.org/schema/tx"             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">                     <bean id="userDao4MySqlImpl" class="com.zs.spring.dao.UserDao4MySqlImpl"/>              <bean id="userManager" class="com.zs.spring.manager.UserManagerImpl">            <property name="userDao" ref="userDao4MySqlImpl"/>        </bean>          </beans>
复制代码

       关于这个XML文件,我会在接下来的文章中重点进行讲解,这里只告诉大家,它的作用就是将对象之间的依赖关系交由Spring容器进行控制,避免硬编码所造成的过度程序耦合。即相当于下面的两句代码:   

UserManager userManager = new UserManagerImpl(userDao);UserDao userDao =  new UserDao4MySqlImpl();

 

  4、总结  

       对比上面的三张类图,我们可以看到,使用Spring框架, 将对象之间的依赖关系交由Spring容器进行控制,通过使用XML文件将对象之间的调用关系从代码中分离,避免硬编码所造成的过度程序耦合,这正是Spring框架实现解耦的核心思想。   

      到此为止,关于Spring的实例就讲解完毕了,讲解的不是很细,大家只需要对Spring框架有一个初步的认识即可。至于Spring运行过程中的具体实现,我会在下次的博文中继续讲解,以便加深大家对Spring的理解。

深入浅出Spring(五) SpringMVC

       上一篇深入浅出Spring(四) Spring实例分析的博文中,咱们已经可以了解Spring框架的运行原理和实现过程,接下来咱们继续讲解Spring的一个延伸产品——Spring MVC 

1、Spring MVC简介

       在开始演示Spring之前,首先来介绍一下Sprig MVC。Spring MVC是一个基于Model2的MVC框架,它围绕DispatcherServlet这个核心类开展,DispatcherServlet是Spring MVC的负责截获客户端请求,组织不同的组件进行请求的处理,对处理的结果进行响应处理。整体实现框架图如下图所示:

2、Spring MVC分析

       大致了解Spring MVC之后,我们做一个简单Spring MVC的实例分析,参考实例已在文章末尾给出链接地址。分析主要从如下几个方面进行:

 A、启用框架

      启用Spring MVC与Struts1相似,就是一个简单的Servlet。通过客户端发送Http请求,web应用服务器接受并判断是否匹配Spring MVC核心类DispatcherServlet的请求路径,如果匹配则转发给DispatcherServlet进行处理。具体的web.xml文件配置参考给出的参考实例。对应上图的如下部分:

       这一部分是Servlet运行过程,与Spring MVC框架本身无关,仅仅是将请求转发到了Spring MVC的核心类,如果有疑惑请参考之前的文章初识Servlets对Servlet运行过程进行了解。 

B、框架执行

       Spring MVC框架的执行比较复杂,这里简单给大家介绍一下,主要分为如下两步:
       1)、DispatcherServelt 接受到Http请求之后,根据这个请求信息以及HandleMapping的配置找到处理请求的处理器Handler。
       2)、找到Handler之后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。

       这里介绍的有点抽象,简单理解就是根据URL地址和这个URL与具体实现类的映射关系(HandleMapping)找到这个实现类(Handler)。具体实现调用的过程是通过使用适配器(HandlerAdapter)对具体实现类(Handler)进行封装,然后调用再统一调用。对应上图的如下部分:

        映射的配置(HandleMapping)方式具体实现主要有两种方式一种是配置文件(具体参考实例代码),另一种是注解实现(具体参考实例代码)。

 C、框架反馈

       Spring MVC框架最终可以反馈给客户端的响应消息的类型非常丰富,可以是一个普通的HTML页面,一个XML或JSON串,也可以是一张图片或一个PDF文档等不同的媒体形式。这里简单介绍一下反馈消息的流程,具体如下;
       1)、Handler处理完成之后,会返回给DispatcherServlet一个ModelAndView
       2)、DispatcherServlet通过ViewResolver中的相关配置,将ModelAndView包含的视图逻辑名解析成真实的视图对象View
       3)、接下来,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染并发送到客户端。

       这个过程具体对应为上图的如下部分:

       以上部分理解起来比较简单与Struts框架基本雷同,这里我们就不做多余的介绍了。

 

       到此关于Spring MVC框架的相关内容,我们就先介绍这么多,以后有时间,我再慢慢给大家介绍。建议大家对比之前的Struts学习,分析两者的不同点和相似之处,这样我们理解和使用就会变得更加灵活。

原创粉丝点击