1. 程式人生 > >Spring的一些零碎知識點整理

Spring的一些零碎知識點整理

Spring Spring配置屬性文件 Web工程中配置Spring 引入Spring配置文件 Spring在web項目中的初始化類

在Web工程中配置Spring

要想在Web工程中配置Spring,首先需要在工程加入spring-web包,我這裏使用的是maven的web工程,pom.xml配置文件配置的依賴如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.14.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.3.14.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>
    </dependencies>

然後在工程的web.xml文件中配置Spring的監聽器,web.xml內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
  <display-name>Archetype Created Web Application</display-name>

  <!-- 配置Spring的監聽器類 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- 配置Spring配置文件的路徑 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:app.xml</param-value>
  </context-param>

</web-app>

這裏的配置要說明一下,在配置Spring配置文件的路徑時,如果你的配置文件放在WEB-INF下是不需要加上 classpath: 前綴的,只需要寫上路徑即可,例如:

  <!-- 配置Spring配置文件的路徑 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/app.xml</param-value>
  </context-param>

完成以上的配置之後,我們先來寫一個簡單的Servlet,並配置上Spring的註解:

package org.zero01.test;

import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component("login")
@WebServlet("/login")
public class LoginServlet extends HttpServlet{

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

然後寫一個測試的Servlet,看看能否從Spring容器中獲得實例對象,在web項目中我們可以通過WebApplicationContextUtils類來幫我們獲取Spring的管理對象:

package org.zero01.test;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.zero01.pojo.Student;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 獲得web工程中的Spring管理對象
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        // 同樣的我們可以通過這個管理對象來獲得我們需要的實例對象
        LoginServlet loginServlet = (LoginServlet) webApplicationContext.getBean("login");
        Student student = (Student) webApplicationContext.getBean("stu");

        // 先打印一下,看看能否獲取到對象
        PrintWriter printWriter = resp.getWriter();
        printWriter.println(loginServlet);
        printWriter.println(student);
    }
}

輸出結果如下:

org.zero01.test.LoginServlet@5afad74f
org.zero01.pojo.Student@1ff85274

如上,可以看到對象已經成功獲取到了,那就代表我們的配置沒有問題,這樣我們就可以在web項目中愉快的使用Spring了。

簡單說明一下WebApplicationContext對象的加載流程:

  • 我們都知道Tomcat啟動時會去加載web.xml文件中的配置,而我們在web.xml配置了Spring的監聽類以及Spring配置文件的路徑

  • 然後Spring的ContextLoaderListener監聽類會監聽著ServletContext的初始化以及銷毀,這一點查看源碼即可得知:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.web.context;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    public ContextLoaderListener() {
    }

    public ContextLoaderListener(WebApplicationContext context) {
        super(context);
    }

    public void contextInitialized(ServletContextEvent event) {
        this.initWebApplicationContext(event.getServletContext());
    }

    public void contextDestroyed(ServletContextEvent event) {
        this.closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}
  • 當ServletContext初始化時會調用該監聽類的contextInitialized方法,而該方法調用了initWebApplicationContext方法並傳遞了ServletContext對象,從方法名的字面意思也可以看出這個方法是用於初始化WebApplicationContext對象的
  • 當WebApplicationContext被初始化時,通過ServletContext對象得到了我們在web.xml中配置的初始化參數,也就是Spring配置文件的路徑,於是Spring的配置文件也被加載起來了,成功加載後,WebApplicationContext對象也就初始化完成了。如果沒被加載起來就會報錯,初始化失敗
  • WebApplicationContext對象初始化完成後,就會存放在ServletContext的屬性裏,這裏就完成了整個加載流程
  • 但是由於我們不知道鍵/值是什麽,所以我們無法直接在ServletContext裏獲得WebApplicationContext對象,而是得通過Spring提供的工具類WebApplicationContextUtils來獲得

多個Spring配置文件

有些情況下,我們可能需要多個配置文件,每個配置文件配置不同的模塊,如下:

技術分享圖片

當需要將這些配置文件都引入一個總的配置文件時,可以使用以下語句:

<import resource="app-aop.xml"/>
<import resource="app-ioc.xml"/>
<import resource="app-tran.xml"/>

Spring配置屬性文件

Spring支持使用屬性文件來配置一些參數,但是這種使用屬性文件來配置參數的方式用得不多,因為很雞肋,而且還會導致到處都是屬性文件的散亂情況。不過有可能在一些特殊的情況下會用到,所以在此也記錄一下,這裏通過配置數據源對象的參數來演示一下如何通過Spring配置屬性文件:

首先創建一個屬性文件dataSourceInfo.properties,文件內容如下:

database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql:///school
database.user=root
database.pw=your_password
database.max.pool.size=10
database.min.pool.size=1
database.loginTimeout=2000

然後編輯Spring的配置內容如下:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       ">

    <!-- 配置屬性文件的路徑 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <array>
                <value>datasourceinfo.properties</value>
            </array>
        </property>
    </bean>

    <!-- 配置數據源對象 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          p:driverClass="${database.driver}"
          p:jdbcUrl="${database.url}"
          p:user="${database.user}"
          p:password="${database.pw}"
          p:maxPoolSize="${database.max.pool.size}"
          p:minPoolSize="${database.min.pool.size}"
          p:loginTimeout="${database.loginTimeout}"
    />

</beans>

測試代碼如下:

package org.zero01.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class Test {

    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("app.xml");
        DataSource dataSource = (DataSource) app.getBean("dataSource");

        try {
            Connection connection = dataSource.getConnection();
            System.out.println(connection);
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

打印結果:

com.mchange.v2.c3p0.impl.NewProxyConnection@3578436e

從打印結果可以看到,數據源對象已經成功拿出來了。但是從整個配置流程可以看到有了Spring後還使用屬性文件來配置參數就有些繞彎子了,這些參數都是可以在Spring配置文件中直接配置的,而且本身Spring的目的之一就是避免存在大量的屬性文件。


Spring在web項目中的初始化類

如果你希望在Tomcat服務器啟動時,初始化一個類,並調用該類中的某個方法時,那麽你就可以通過實現Spring中的兩個接口來完成。首先是InitializingBean接口,實現這個接口的類會在Tomcat服務器啟動時被初始化並調用其中的afterPropertiesSet方法:

package org.zero01.test;

import org.springframework.beans.factory.InitializingBean;

public class InitBean implements InitializingBean {

    public void afterPropertiesSet() throws Exception {
        System.out.println("我被初始化了 —— InitializingBean");
    }
}

另一個接口是 ApplicationListener ,這個接口的方法有數據源參數,所以這個方法可以完成更多的事情,而且當你有某個邏輯是必須要等到所有的bean都被處理完成之後再執行的話,就適合使用這個接口,因為所有的bean都被處理完成之後這個接口的方法才會被調用:

package org.zero01.test;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class AppInit implements ApplicationListener{
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println("我被初始化了 —— ApplicationListener");
    }
}

然後需要配置一下這兩個類,Spring配置文件內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       ">

    <bean class="org.zero01.test.AppInit"/>
    <bean class="org.zero01.test.InitBean"/>

</beans>

完成配置後啟動Tomcat服務器,Tomcat服務器啟動時輸出結果如下:
技術分享圖片

可以看到,實現 InitializingBean 接口的類比實現 ApplicationListener 接口的類先被初始化。所以它們之間還是有一些區別的,需要根據具體的業務場景來進行使用哪一個接口。


通過實現接口獲得ApplicationContext或者BeanFacrory的對象

通過實現接口獲得ApplicationContext對象,代碼如下:

package org.zero01.test;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Test implements ApplicationContextAware {

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        LoginServlet loginServlet = (LoginServlet) applicationContext.getBean("login");
    }
}

通過實現接口獲得BeanFacrory對象,代碼如下:

package org.zero01.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

public class Test implements BeanFactoryAware {

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        LoginServlet loginServlet = (LoginServlet) beanFactory.getBean("login");
    }
}

Spring的一些零碎知識點整理