首页 > 代码库 > J2EE知识整理(二)

J2EE知识整理(二)

  就在前不久,一个资深JAVA经理兼HR跟我说,做Java web的,一定要会Spring,不止是会用,还要深入进去,看看它的实现原理,以及是怎么编写的,对此我表示鸭梨很大,内部结构,原理啥都只能先放着一遍,先来看看Spring是怎么做的。

 

IOC?DI?这是个咩啊!

  关于控制反转或者说依赖注入到底是个什么意思,这里就不多加说明了,Spring in Action专业度爆脖主的距离怕有该书作者到脖主的地理位置那么远,还是直接来看看是怎么做的吧

  public class DbInfoServlet extends HttpServlet{

    public void service(HttpServletRequest request,HttpServletResponse response)

      throws ServletException,java.io.IOException{

      request.setCharacterEncoding("GBK");

      DbInfo dbinfo = new DbInfo();

      String result = dbinfo.queryModelInfo();

      response.setContentType("text/html;charset=UTF-8");

      response.setHeader("Cache-Control", "no-cache");

             PrintStream out = new PrintStream(response.getOutputStream());

             out.println(result);

    }

  }

 

  这是上篇中的一个servlet应用,对于类DbInfo 的使用,通过new一个新实例来实现。

 

  public class ModelInfoControl implements Controller {

    private ModelInfoService modelInfoService;

 

       @Override

     public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response)

             throws ServletException,java.io.IOException{

           request.setCharacterEncoding("GBK");

      String result = modelInfoService.queryModelInfo();

      response.setContentType("text/html;charset=UTF-8");

             response.setHeader("Cache-Control", "no-cache");

           PrintStream out = new PrintStream(response.getOutputStream());

           out.println(result);

           out.flush();

             out.close();

           return null;

    }

       public void setModelInfoService(ModelInfoService modelInfoService) {

           this.modelInfoService = modelInfoService;

       }

  }

 

  虽然命名略有不同,但是不影响看出差别,这里ModelInfoService类实例modelInfoService,没有使用new关键字去创建,而且在下方,多出了一个他的set方法。

这是如何实现的,我们呼应一下标题,在这里,创建被调用者实例的工作不在由调用者完成,而是在外部实现后注入调用者,所以说,这里控制反转了或者说,这里依赖注入,那么。新的问题出现了,现在,控制反转到谁头上了,依赖于谁去注入?

容器

  暂时让我们忘掉之前的MyProject,忘掉上面的对于依赖注入的说明,来看一个Spring的简单应用:

定义两个接口,斧子和人

  public interface Axe {

        public String chop();

  }

  public interface Person {

        public void useAxe();

  }

 

  定义斧子的实现类

  public class StoneAxe implements Axe {

    @Override

    public String chop() {

             // TODO Auto-generated method stub

             return "石斧砍柴好慢";

    }

  }

  以及人的实现类

  public class Chinese{

    private Axe axe;

    public void setAxe(Axe axe) {

             this.axe = axe;

          }  

          public Axe getAxe() {

            return axe;

            }

  }

  最后测试Spring

  public class SpringTest {

        public static void main(String[] args) {

      ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");

             Chinese p = ctx.getBean("chinese",Chinese.class);

             System.out.println(p.getAxe().chop());

         }

  }

  输出:石斧砍柴好慢

 

  但是,等等,这是怎么一回事,Chinese里明明是个接口的axe,是怎么变成StoneAxe的实例的!

  我们先关注一下chinese实例p的创建。

  ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");

  Chinese p = ctx.getBean("chinese",Chinese.class);

  想到什么没,虽然跟上面的方式不太一样,但是显然这里的p也没通过new关键字创建,而是通过一个叫ctx的ApplicationContext实例创建,而ctx,显然借助了数据文件bean.xml来实现自身的实例化。

  我们来看一下bean.xml。

  <?xml version="1.0" encoding="UTF-8"?>

  <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

    xmlns="http://www.springframework.org/schema/beans"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 

      <bean id="chinese" class="sun.service.Chinese">

          <property name="axe" ref="stoneAxe"/>

      </bean>

      <bean id="stoneAxe" class="sun.service.StoneAxe"/>

  </beans>

  这里定义了两个bean Chinese chinese和StoneAxe stoneAxe,而chinese的参数axestoneAxe的一个实现。

  这下就好理解了,p是ctx所获取的bean chinese,这个Chinese类的实例中,属性axe为bean stoneAxe看到这里,前面的问题也就呼之欲出了,ApplicationContext类作为了各个Spring实例中被调用实例的控制和注入者,我们将其称呼为容器,装纳bean的容器。

Spring的Web应用,Spring MVC

  扯远了点,还是回到项目中来,添加容器配置文件applicationContext.xml

  <?xml version="1.0" encoding="UTF-8"?>

  <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          

    xmlns="http://www.springframework.org/schema/beans"         

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  </beans>

  并在web.xml里对其进行配置

  <listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

  </listener>

  <context-param>

        <param-name>contextConfigLocation</param-name>

          <param-value>classpath:applicationContext.xml</param-value>

  </context-param>

 

  定义接口ModelInfoDao和实现类ModelInfoDaoImpl

  public interface ModelInfoDao {

        //获取模块信息

         String queryModelInfo();

  }

  public class ModelInfoDaoImpl implements ModelInfoDao {

        Connection conn = null

        Statement stmt = null

          ResultSet rs = null;

   

         public String queryModelInfo(){

       String result = "";

       try {

         Class.forName("oracle.jdbc.driver.OracleDriver"); 

         conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "Leon", "orcl");

         stmt = conn.createStatement();

                    rs = stmt.executeQuery("select * from t_model_info");

         while(rs.next()){

           result =rs.getString("info");

         }

       } catch (ClassNotFoundException e) {

         e.printStackTrace();

       } catch (SQLException e) {

         e.printStackTrace();

       } finally {

        try {

          if(conn != null) {

              conn.close();

              conn = null;

            }

        } catch (SQLException e) {

          e.printStackTrace(); 

                   } 

              } 

              return result;

    }

  }

  注册ModelInfoDaoImpl 的实例bean modelInfoDao。

  <bean id="modelInfoDao" class="dao.ModelInfoDaoImpl"/>

 

  定义接口ModelInfoService和实现类ModelInfoServiceImpl

  public interface ModelInfoService {

         String queryModelInfo();

   }

  public class ModelInfoServiceImpl implements ModelInfoService {

 

         private ModelInfoDao modelInfo;

     @Override

            public String queryModelInfo() {

                String result = modelInfo.queryModelInfo();

                return result;

            }

            public void setDbInfo(ModelInfoDao dbInfo) {

                  this.modelInfo = dbInfo;

            }

            public ModelInfoDao getModelInfo() {

                   return modelInfo;

            }

            public void setModelInfo(ModelInfoDao modelInfo) {

                   this.modelInfo = modelInfo;

            }

  }

 

  注册ModelInfoServiceImpl的实例bean modelInfoServiceImpl,并将bean modelInfoDao作为参数modelInfo注入其中。

  <bean id="modelInfoService" class="service.ModelInfoServiceImpl">

       <property name="modelInfo" ref="modelInfoDao" />

  </bean>

 

  OK,这里,bean的准备都已经做好,只需等候召唤了。

  话说,召唤个皮卡丘都要靠精灵球网络控制,前台请求呢

控制器

  正如其命名,DispatcherServlet类来作为前置控制器,通过拦截接受前台匹配的请求请求,将其调度到指定的控制器中。

  <servlet>

    <servlet-name>dispatcher</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <load-on-startup>1</load-on-startup>

  </servlet>

  <servlet-mapping>

      <servlet-name>dispatcher</servlet-name>

      <url-pattern>*.htm</url-pattern>

  </servlet-mapping>

 

  这里还需要为其添加配置文件,用来指定请求与控制器的关系

  注意,这里配置文件命名规则为”servlet-name” + ”-servlet.xml”,存放在WEB-INF下(可通过配置修改命名与存放路径),如此处为dispatcher-servlet.xml:

  <?xml version="1.0" encoding="UTF-8"?>

  <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns="http://www.springframework.org/schema/beans"

      xsi:schemaLocation="http://www.springframework.org/schema/beans

      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   

  </beans>

 

  添加控制器ModelInfoControl

    public class ModelInfoControl implements Controller {

      private ModelInfoService modelInfoService;

       

      @Override

      public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,java.io.IOException{

        request.setCharacterEncoding("GBK");

          

        String result = modelInfoService.queryModelInfo();

               response.setContentType("text/html;charset=UTF-8");

               response.setHeader("Cache-Control", "no-cache");

               PrintStream out = new PrintStream(response.getOutputStream());

               out.println(result);

               out.flush();

               out.close();

               return null;

          }

          public void setModelInfoService(

       ModelInfoService modelInfoService) {

              this.modelInfoService = modelInfoService;

          }

     }

  并将其在dispatcher-servlet.xml中注册,并将bean modelInfoService作为参数实例注入

  <bean name="/modelInfo.htm" class="control.ModelInfoControl">

    <property name="modelInfoService">

             <ref bean="modelInfoService"/>

    </property>

  </bean>

 

  修改前台页面请求,这次我们不请求servlet了,我们走Spring这条路

 

  "./dbInfoServlet" —> "modelInfo.htm"

 

  执行项目,看到醒目的首页两个字,开心~