搜索词>>

spring������

耗时0.0030
  • java c++通用DES/AES对称加密算法(包含源代码)

    java c++通用DES加密算法(包含源代码),本来觉得DES、AES这种流行加密算法,使用起来应该很简单。但研究后发现有两个变数:1分块的方式。加密是逐块进行的。2.padding的方式。当数据的位数不及块的大小时,需要填充。<h2>一说明</h2> 本来觉得DES、AES这种流行加密算法,使用起来应该很简单。但研究后发现有两个变数: <ul> <li>分块的方式。加密是逐块进行的。分块方法有:CBC、ECB、CFB……</li> <li>padding的方式。当数据的位数不及块的大小时,需要填充。填充方式有:NoPadding、PKCS5Padding……</li> </ul> 如果加解密端采用不同的分块方式或padding方式,即使都是采用DES/AES算法,同样无法解密成功。上次需要C端和Java端进行密文传输,就跪在这一点上(那时候没时间研究)。<br /> 参考文章:<a href="http://my.oschina.net/u/267094/blog/174035" rel="external nofollow" target="_blank">Java AES算法和openssl配对</a> ,主要通过其了解openssl里比较高级的EVP系列API(其默认padding和java一样都是PKCS5Padding),节约了搜索时间。<br /> 贴代码了,以下代码测试通过了。Java和C++均可以正确解密对方的密文。<br /> 约定:分块和padding采用Java默认的 ECB + PKCS5Padding。 <h2>二 DES加解密</h2> <h3>Java端DES加解密</h3> <pre> <code class="language-java">import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class DESUtil { /** 默认算法格式 **/ static String default_transformation = "DES/ECB/PKCS5Padding"; /** * 根据key获取加密器 * * @param keyData * key 8byte * @return 加密器 * @throws Exception * 异常 */ private static Cipher getEncryptCipher(byte[] keyData) throws Exception { if (keyData.length != 8) { throw new Exception("Key Data Must 8 byte!"); } SecretKeySpec key = new SecretKeySpec(keyData, "DES"); // 指定分块ECB模式,填充PKCS5Padding模式 Cipher encryptCipher = Cipher.getInstance(default_transformation); // 初始化加密的容器 encryptCipher.init(Cipher.ENCRYPT_MODE, key); return encryptCipher; } /** * 根据key获取解码器 * * @return 解码器 * @throws Exception * 异常 */ private static Cipher getDecryptCipher(byte[] keyData) throws Exception { if (keyData.length != 8) { throw new Exception("Key Data Must 8 byte!"); } SecretKeySpec key = new SecretKeySpec(keyData, "DES"); Cipher decryptCipher = Cipher.getInstance(default_transformation); // 初始化解密的容器 decryptCipher.init(Cipher.DECRYPT_MODE, key); return decryptCipher; } /** * DES加密 * * @param data * 待加密数据 * @param keyData * key值 * @return 加密后的数据 * @throws Exception * 异常 */ public static byte[] encrypt(byte[] data, byte[] keyData) throws Exception { return getEncryptCipher(keyData).doFinal(data); } /** * DES解密 * * @param data * 加密后的数据 * * @param keyData * key值 * @return 解密数据 * @throws Exception * 异常 */ public static byte[] decrypt(byte[] data, byte[] keyData) throws Exception { return getDecryptCipher(keyData).doFinal(data); } /** * 测试 * * @param args */ public static void main(String[] args) { try { byte[] data = "测试123456".getBytes(); byte[] keyData = "12345678".getBytes(); System.out.println("原文:" + new String(data)); byte[] enData = encrypt(data, keyData); System.out.println("加密后:" + new String(enData)); byte[] deData = decrypt(enData, keyData); System.out.println("解密后:" + new String(deData)); } catch (Exception e) { e.printStackTrace(); } } } </code></pre> <strong><span style="color:#27ae60">说明:Java必须指定填充模式和padding模式。DES/ECB/PKCS5Padding,好与C++同步</span></strong><br /> 测试执行结果: <pre> <code class="language-html">原文:测试123456 加密后:�a���O���?I�]�Y 解密后:测试123456</code></pre> <h3>C++端DES加解密</h3> c++DES加密代码 <pre> <code class="language-cpp">#include <string> #include <iostream> #include <stdio.h> #include <assert.h> #include <openssl/objects.h> #include <openssl/evp.h> // 注意:参数和返回值全部是二进制数据 std::string desEncrypt(const std::string& source, const std::string& key) {     EVP_CIPHER_CTX ctx;     EVP_CIPHER_CTX_init(&ctx);     int ret = EVP_EncryptInit_ex(&ctx, EVP_des_ecb(), NULL, (const unsigned char*)key.data(), NULL);     assert(ret == 1);     unsigned char* result = new unsigned char[source.length() + 64]; // 弄个足够大的空间     int len1 = 0;     ret = EVP_EncryptUpdate(&ctx, result, &len1, (const unsigned char*)source.data(), source.length());     assert(ret == 1);     int len2 = 0;     ret = EVP_EncryptFinal_ex(&ctx, result+len1, &len2);      assert(ret == 1);     std::cout << len1 << "," << len2 << std::endl;     ret = EVP_CIPHER_CTX_cleanup(&ctx);     assert(ret == 1);     std::string res((char*)result, len1+len2);     delete[] result;     return res; } int main() {     std::string key("hellodes", 8);    // 二进制数据,而不是以0结尾的字符串     // 读取文件内容(简单起见认为文件内容<100K)     char buf[1024*100];     FILE* fp = fopen("src.txt", "rb");     int bytes = fread(buf, 1, 1024*100, fp);     fclose(fp);     std::string source(buf, bytes); // 二进制数据     // 加密     std::string enc = desEncrypt(source, key);     std::cout << "desEncrypt:" << source.length() << "->" << enc.length() << std::endl;     // 输出到文件     fp =  fopen("enc.bin", "wb");     fwrite(enc.data(), 1, enc.length(), fp);     fclose(fp); }</code></pre> c++DES解密 <pre> <code class="language-cpp">#include <string> #include <iostream> #include <stdio.h> #include <assert.h> #include <openssl/objects.h> #include <openssl/evp.h> // 注意:参数和返回值全部是二进制数据 std::string desDecrypt(const std::string& ciphertext, const std::string& key) {     EVP_CIPHER_CTX ctx;     EVP_CIPHER_CTX_init(&ctx);     int ret = EVP_DecryptInit_ex(&ctx, EVP_des_ecb(), NULL, (const unsigned char*)key.data(), NULL);     assert(ret == 1);     unsigned char* result = new unsigned char[ciphertext.length() + 64]; // 弄个足够大的空间     int len1 = 0;     ret = EVP_DecryptUpdate(&ctx, result, &len1, (const unsigned char*)ciphertext.data(), ciphertext.length());     assert(ret == 1);     int len2 = 0;     ret = EVP_DecryptFinal_ex(&ctx, result+len1, &len2);      assert(ret == 1);     std::cout << len1 << "," << len2 << std::endl;     ret = EVP_CIPHER_CTX_cleanup(&ctx);     assert(ret == 1);     std::string res((char*)result, len1+len2);     delete[] result;     return res; } int main() {     std::string key("hellodes", 8);    // 二进制数据,而不是以0结尾的字符串     // 读取文件内容(简单起见认为文件内容<100K)     char buf[1024*100];     FILE* fp = fopen("enc.bin", "rb");     int bytes = fread(buf, 1, 1024*100, fp);     fclose(fp);     std::string data(buf, bytes); // 二进制数据     // 加密     std::string dec = desDecrypt(data, key);     std::cout << "desDecrypt:" << data.length() << "->" << dec.length() << std::endl;     // 输出到文件     fp =  fopen("dec.txt", "wb");     fwrite(dec.data(), 1, dec.length(), fp);     fclose(fp); }</code></pre> <br /> 说明:DES、AES加密算法都是针对数据块,Java加解密函数参数使用byte数组。C++用std::string,那是因为这是C++中使用byte数组的最简单方式(std::string可以存储二进制数据,很多人没想到吧),缺点是拷贝内存的次数可能会略多些。如果想要优化拷贝效率,可以使用自己封装的Buffer类来代替std::string。 <h2>三 AES加解密</h2> <h3>Java端AES加解密</h3> <pre> <code class="language-java">import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; /** * DES加解密算法工具类 * * @author xqlee * */ public class AESUtil { /** 默认算法格式 **/ static String default_transformation = "AES/ECB/PKCS5Padding"; /** * 根据key获取加密器 * * @param keyData * key 8byte * @return 加密器 * @throws Exception * 异常 */ private static Cipher getEncryptCipher(byte[] keyData) throws Exception { if (keyData.length != 16) { throw new Exception("Key Data Must 8 byte!"); } SecretKeySpec key = new SecretKeySpec(keyData, "AES"); // 指定分块ECB模式,填充PKCS5Padding模式 Cipher encryptCipher = Cipher.getInstance(default_transformation); // 初始化加密的容器 encryptCipher.init(Cipher.ENCRYPT_MODE, key); return encryptCipher; } /** * 根据key获取解码器 * * @return 解码器 * @throws Exception * 异常 */ private static Cipher getDecryptCipher(byte[] keyData) throws Exception { if (keyData.length != 16) { throw new Exception("Key Data Must 8 byte!"); } SecretKeySpec key = new SecretKeySpec(keyData, "AES"); Cipher decryptCipher = Cipher.getInstance(default_transformation); // 初始化解密的容器 decryptCipher.init(Cipher.DECRYPT_MODE, key); return decryptCipher; } /** * AES加密 * * @param data * 待加密数据 * @param keyData * key值 * @return 加密后的数据 * @throws Exception * 异常 */ public static byte[] encrypt(byte[] data, byte[] keyData) throws Exception { return getEncryptCipher(keyData).doFinal(data); } /** * AES解密 * * @param data * 加密后的数据 * * @param keyData * key值 * @return 解密数据 * @throws Exception * 异常 */ public static byte[] decrypt(byte[] data, byte[] keyData) throws Exception { return getDecryptCipher(keyData).doFinal(data); } /** * 测试 * * @param args */ public static void main(String[] args) { try { byte[] data = "测试123456".getBytes(); byte[] keyData = "1234567887654321".getBytes(); System.out.println("原文:" + new String(data)); byte[] enData = encrypt(data, keyData); System.out.println("加密后:" + new String(enData)); byte[] deData = decrypt(enData, keyData); System.out.println("解密后:" + new String(deData)); } catch (Exception e) { e.printStackTrace(); } } } </code></pre> <h3>C++端AES加解密</h3> 加密: <pre> <code class="language-cpp">#include <string> #include <iostream> #include <stdio.h> #include <assert.h> #include <openssl/objects.h> #include <openssl/evp.h> // 注意:参数和返回值全部是二进制数据 std::string aesEncrypt(const std::string& source, const std::string& key) {     EVP_CIPHER_CTX ctx;     EVP_CIPHER_CTX_init(&ctx);     int ret = EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, (const unsigned char*)key.data(), NULL);     assert(ret == 1);     unsigned char* result = new unsigned char[source.length() + 64]; // 弄个足够大的空间     int len1 = 0;     ret = EVP_EncryptUpdate(&ctx, result, &len1, (const unsigned char*)source.data(), source.length());     assert(ret == 1);     int len2 = 0;     ret = EVP_EncryptFinal_ex(&ctx, result+len1, &len2);      assert(ret == 1);     std::cout << len1 << "," << len2 << std::endl;     ret = EVP_CIPHER_CTX_cleanup(&ctx);     assert(ret == 1);     std::string res((char*)result, len1+len2);     delete[] result;     return res; } int main() {     std::string key("helloaeshelloaes", 16);    // 二进制数据,而不是以0结尾的字符串     // 读取文件内容(简单起见认为文件内容<100K)     char buf[1024*100];     FILE* fp = fopen("src.txt", "rb");     int bytes = fread(buf, 1, 1024*100, fp);     fclose(fp);     std::string source(buf, bytes); // 二进制数据     // 加密     std::string enc = aesEncrypt(source, key);     std::cout << "aesEncrypt:" << source.length() << "->" << enc.length() << std::endl;     // 输出到文件     fp =  fopen("enc.bin", "wb");     fwrite(enc.data(), 1, enc.length(), fp);     fclose(fp); }</code></pre> 解密: <pre> <code class="language-cpp">#include <string> #include <iostream> #include <stdio.h> #include <assert.h> #include <openssl/objects.h> #include <openssl/evp.h> // 注意:参数和返回值全部是二进制数据 std::string aesDecrypt(const std::string& ciphertext, const std::string& key) {     EVP_CIPHER_CTX ctx;     EVP_CIPHER_CTX_init(&ctx);     int ret = EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, (const unsigned char*)key.data(), NULL);     assert(ret == 1);     unsigned char* result = new unsigned char[ciphertext.length() + 64]; // 弄个足够大的空间     int len1 = 0;     ret = EVP_DecryptUpdate(&ctx, result, &len1, (const unsigned char*)ciphertext.data(), ciphertext.length());     assert(ret == 1);     int len2 = 0;     ret = EVP_DecryptFinal_ex(&ctx, result+len1, &len2);      assert(ret == 1);     std::cout << len1 << "," << len2 << std::endl;     ret = EVP_CIPHER_CTX_cleanup(&ctx);     assert(ret == 1);     std::string res((char*)result, len1+len2);     delete[] result;     return res; } int main() {     std::string key("helloaeshelloaes", 16);    // 二进制数据,而不是以0结尾的字符串     // 读取文件内容(简单起见认为文件内容<100K)     char buf[1024*100];     FILE* fp = fopen("enc.bin", "rb");     int bytes = fread(buf, 1, 1024*100, fp);     fclose(fp);     std::string data(buf, bytes); // 二进制数据     // 加密     std::string dec = aesDecrypt(data, key);     std::cout << "aesDecrypt:" << data.length() << "->" << dec.length() << std::endl;     // 输出到文件     fp =  fopen("dec.txt", "wb");     fwrite(dec.data(), 1, dec.length(), fp);     fclose(fp); }</code></pre>
  • Spring Context 与Spring MVC Context

    Spring Context 与Spring MVC Context那些坑<h2>引言</h2> Spring Context与Spring MVC容器常见的问题和疑问讲解。 <h2>一.Spring MVC WEB配置</h2> <p>Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext,使得拥有web功能。那么,Spring MVC是如何在web环境中创建IoC容器呢?web环境中的IoC容器的结构又是什么结构呢?web环境中,Spring IoC容器是怎么启动呢?</p> <p>  以Tomcat为例,在Web容器中使用Spirng MVC,必须进行四项的配置:</p> <ul> <li> <p>修改web.xml,添加servlet定义;</p> </li> <li> <p>编写servletname-servlet.xml(servletname是在web.xm中配置DispactherServlet时使servlet-name的值)配置;</p> </li> <li> <p>contextConfigLocation初始化参数、配置ContextLoaderListerner; </p> </li> </ul> <p>Web.xml配置如下:<br />  </p> <pre> <code class="language-xml"><!-- servlet定义:前端处理器,接受的HTTP请求和转发请求的类 --> <servlet> <servlet-name>court</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- court-servlet.xml:定义WebAppliactionContext上下文中的bean --> <param-name>contextConfigLocation</param-name> <param-value>classpath*:court-servlet.xml</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>court</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 配置contextConfigLocation初始化参数:指定Spring IoC容器需要读取的定义了非web层的Bean(DAO/Service)的XML文件路径 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/court-service.xml</param-value> </context-param> <!-- 配置ContextLoaderListerner:Spring MVC在Web容器中的启动类,负责Spring IoC容器在Web上下文中的初始化 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener></code></pre>   <p>在web.xml配置文件中,有两个主要的配置:ContextLoaderListener和DispatcherServlet。同样的关于spring配置文件的相关配置也有两部分:context-param和DispatcherServlet中的init-param。那么,这两部分的配置有什么区别呢?它们都担任什么样的职责呢?</p> <p> </p> <p>  在Spring MVC中,Spring Context是以父子的继承结构存在的。Web环境中存在一个ROOT Context,这个Context是整个应用的根上下文,是其他context的双亲Context。同时Spring MVC也对应的持有一个独立的Context,它是ROOT Context的子上下文。</p> <p> </p> <p>  对于这样的Context结构在Spring MVC中是如何实现的呢?下面就先从ROOT Context入手,ROOT Context是在ContextLoaderListener中配置的,ContextLoaderListener读取context-param中的contextConfigLocation指定的配置文件,创建ROOT Context。</p> <p> </p> <p>Spring MVC启动过程大致分为两个过程:</p> <ol> <li> <p>ContextLoaderListener初始化,实例化IoC容器,并将此容器实例注册到ServletContext中;</p> </li> <li> <p>DispatcherServlet初始化;</p> </li> </ol> <h2>二.Web容器中Spring根上下文的加载与初始化</h2> <p>   Web容器调用contextInitialized方法初始化ContextLoaderListener,在此方法中,ContextLoaderListener通过调用继承自ContextLoader的initWebApplicationContext方法实例化Spring Ioc容器。</p> <p> </p> <p>  先看一下WebApplicationContext是如何扩展ApplicationContext来添加对Web环境的支持的。WebApplicationContext接口定义如下:<br />  </p> <pre> <code class="language-java">public interface WebApplicationContext extends ApplicationContext { //根上下文在ServletContext中的名称 String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; //取得web容器的ServletContext ServletContext getServletContext(); }</code></pre> <br /> 下面看一下ContextLoaderListener中创建context的源码:ContextLoader.java <pre> <code class="language-java">public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { //PS : ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=WebApplicationContext.class.getName() + ".ROOT" 根上下文的名称 //PS : 默认情况下,配置文件的位置和名称是: DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml" //在整个web应用中,只能有一个根上下文 if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException("Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { // 在这里执行了创建WebApplicationContext的操作 this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> // determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } // PS: 将根上下文放置在servletContext中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if (ccl != null) { currentContextPerThread.put(ccl, this.context); } if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }</code></pre> 再看一下WebApplicationContext对象是如何创建的:ContextLoader.java <pre> <code class="language-java">protected WebApplicationContext createWebApplicationContext(ServletContext sc, ApplicationContext parent) { //根据web.xml中的配置决定使用何种WebApplicationContext。默认情况下使用XmlWebApplicationContext //web.xml中相关的配置context-param的名称“contextClass” Class<?> contextClass = determineContextClass(sc); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } //实例化WebApplicationContext的实现类 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); // Assign the best possible id value. if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { // Servlet <= 2.4: resort to name specified in web.xml, if any. String servletContextName = sc.getServletContextName(); if (servletContextName != null) { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName); } else { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX); } } else { // Servlet 2.5's getContextPath available! wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + sc.getContextPath()); } wac.setParent(parent); wac.setServletContext(sc); //设置spring的配置文件 wac.setConfigLocation(sc.getInitParameter(CONFIG_LOCATION_PARAM)); customizeContext(sc, wac); //spring容器初始化 wac.refresh(); return wac; }</code></pre> ContextLoaderListener构建Root Context时序图:<br /> <img alt="Spring Context" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/477cdee6630644738ce9c6386ad886c5.gif" /> <h2>三.Spring MVC对应的上下文加载与初始化</h2> <p>Spring MVC中核心的类是DispatcherServlet,在这个类中完成Spring context的加载与创建,并且能够根据Spring Context的内容将请求分发给各个Controller类。DispatcherServlet继承自HttpServlet,关于Spring Context的配置文件加载和创建是在init()方法中进行的,主要的调用顺序是init-->initServletBean-->initWebApplicationContext。</p> <p>先来看一下initWebApplicationContext的实现:FrameworkServlet.java<br />  </p> <pre> <code class="language-java">protected WebApplicationContext initWebApplicationContext() { //先从web容器的ServletContext中查找WebApplicationContext WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { // No fixed context defined for this servlet - create a local one. //从ServletContext中取得根上下文 WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); //创建Spring MVC的上下文,并将根上下文作为起双亲上下文 wac = createWebApplicationContext(parent); } if (!this.refreshEventReceived) { // Apparently not a ConfigurableApplicationContext with refresh support: // triggering initial onRefresh manually here. onRefresh(wac); } if (this.publishContext) { // Publish the context as a servlet context attribute. // 取得context在ServletContext中的名称 String attrName = getServletContextAttributeName(); //将Spring MVC的Context放置到ServletContext中 getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; }</code></pre>     通过initWebApplicationContext方法的调用,创建了DispatcherServlet对应的context,并将其放置到ServletContext中,这样就完成了在web容器中构建Spring IoC容器的过程。<br /> <br />     DispatcherServlet创建context时序图:<br /> <img alt="Spring框架" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/a9d2eacfb40947ecb425fa840d45dead.gif" /><br /> <br /> DispatcherServlet初始化的大体流程:<br /> <img alt="DispatcherServlet初始化的大体流程:" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/adff9a97f46b40bda975a3127e7fdc53.gif" /><br /> 控制器DispatcherServlet的类图及继承关系:<br /> <img alt="333" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/234bbfda94ca446784d555f51379f726.jpg" /><br />   <h2>四.Spring中DispacherServlet、WebApplicationContext、ServletContext的关系</h2> <p>要想很好理解这三个上下文的关系,需要先熟悉Spring是怎样在web容器中启动起来的。Spring的启动过程其实就是其IOC容器的启动过程,对于web程序,IOC容器启动过程即是建立上下文的过程。</p> <p> </p> <p><strong>Spring的启动过程:</strong></p> <ol> <li> <p>首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;</p> </li> <li> <p>其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取; </p> </li> <li> <p>再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有spring mvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是mlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。</p> <p> </p> </li> </ol> <p><strong>在Web容器(比如Tomcat)中配置Spring时,你可能已经司空见惯于web.xml文件中的以下配置代码:</strong><br />  </p> <pre> <code class="language-xml"><context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></span></code></pre> 以上配置首先会在ContextLoaderListener中通过<context-param>中的applicationContext.xml创建一个ApplicationContext,再将这个ApplicationContext塞到ServletContext里面,通过ServletContext的setAttribute方法达到此目的,在ContextLoaderListener的源代码中,我们可以看到这样的代码: <pre> <code class="language-java">servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);</code></pre> 以上由ContextLoaderListener创建的ApplicationContext是共享于整个Web应用程序的,而你可能早已经知道,DispatcherServlet会维持一个自己的ApplicationContext,默认会读取/WEB-INFO/<dispatcherServletName>-servlet.xml文件,而也可以重新配置: <pre> <code class="language-xml"><servlet> <servlet-name> customConfiguredDispacherServlet </servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name> contextConfigLocation </param-name> <param-value> /WEB-INF/dispacherServletContext.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet></code></pre> <p><strong>问题是:以上两个ApplicationContext的关系是什么,它们的作用作用范围分别是什么,它们的用途分别是什么?</strong></p> <p>  ContextLoaderListener中创建ApplicationContext主要用于整个Web应用程序需要共享的一些组件,比如DAO,数据库的ConnectionFactory等。而由DispatcherServlet创建的ApplicationContext主要用于和该Servlet相关的一些组件,比如Controller、ViewResovler等。</p> <p>  对于作用范围而言,在DispatcherServlet中可以引用由ContextLoaderListener所创建的ApplicationContext,而反过来不行。</p> <p>在Spring的具体实现上,这两个ApplicationContext都是通过ServletContext的setAttribute方法放到ServletContext中的。但是,ContextLoaderListener会先于DispatcherServlet创建ApplicationContext,DispatcherServlet在创建ApplicationContext时会先找到由ContextLoaderListener所创建的ApplicationContext,再将后者的ApplicationContext作为参数传给DispatcherServlet的ApplicationContext的setParent()方法,在Spring源代码中,你可以在FrameServlet.java中找到如下代码:<br />  </p> <pre> <code class="language-java">wac.setParent(parent);</code></pre> <p>其中,wac即为由DisptcherServlet创建的ApplicationContext,而parent则为有ContextLoaderListener创建的ApplicationContext。此后,框架又会调用ServletContext的setAttribute()方法将wac加入到ServletContext中。</p> <p>  当Spring在执行ApplicationContext的getBean时,如果在自己context中找不到对应的bean,则会在父ApplicationContext中去找。这也解释了为什么我们可以在DispatcherServlet中获取到由ContextLoaderListener对应的ApplicationContext中的bean。</p>
  • Spring WebFlux

    Spring WebFlux,spring框架5.0将会新增的web增强框架,这里主要讲述什么是Spring WebFlux以及Spring WebFlux的新功能,Spring WebFlux与Spring MVC的关系。<h2><img alt="spring boot2.0 spring5.0" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-10/760dfcfe492b4e4b8c5fa8f2f899ea29.png" /><br /> 1.Spring WebFlux简介</h2>   包含在Spring框架中的原始Web框架Spring Web MVC是为Servlet API和Servlet容器而设计的。 反过来的堆栈,Web框架,Spring WebFlux,稍后在版本5.0中添加。 它是完全非阻塞的,支持反向流反向压力,并在诸如Netty,Undertow和Servlet 3.1+容器之类的服务器上运行。<br /> <br />   这两个Web框架镜像了Spring模块的名称spring-webmvc和spring-webflux,并在Spring框架中并存。 每个模块都是可选的。 应用可以使用一个或另一个模块,或者在一些情况下可以使用例如。 具有反应WebClient的Spring MVC控制器。<br /> <br />   除了Web框架之外,Spring WebFlux还提供了用于执行HTTP请求的WebClient,用于测试Web端点的WebTestClient以及客户端和服务器反应的WebSocket支持。 <h2>2.为何要新增一个web框架?</h2>   答案的一部分是需要一个非阻塞的Web栈来处理与少量线程的并发,并以较少的硬件资源进行扩展。 Servlet 3.1确实为非阻塞I / O提供了API。但是,使用它会远离Servlet API的其他部分,其中合同是同步的(Filter,Servlet)或阻塞(getParameter,getPart)。这是新的通用API作为任何非阻塞运行时基础的动机。这一点很重要,因为Netty这样的服务器在异步非阻塞空间中已经建立起来了。<br /> <br />   答案的另一部分是功能编程。很像在Java 5中添加注释创造的机会 - 例如。注释的REST控制器或单元测试,在Java 8中添加lambda表达式为Java中的功能API创造了机会。这对于非阻塞应用程序和连续样式API是一个福音 - 由CompletableFuture和ReactiveX普及,允许异步逻辑的声明性组合。在编程模型级别,Java 8启用了Spring WebFlux,可以为注释控制器提供功能性的Web端点。 <h2>3.Reactive什么和为什么?</h2>   我们触及非阻塞和功能,但为什么反应性,我们的意思是什么?<br /> <br />   术语“反应性”是指围绕响应变化构建的编程模型 - 网络组件对I / O事件的响应,UI控制器对鼠标事件的反应等。在这个意义上,非阻塞是反应的,因为不是被阻止现在在作为操作完成或数据变得可用的响应通知的模式。<br /> <br />   还有一个重要的机制,我们在春季团队与“反应”相关联,这是非阻碍的背压。在同步的命令式代码中,阻止调用可以作为强制呼叫者等待的背部压力的自然形式。在非阻塞代码中,重要的是控制事件的速率,以便快速生产者不会压倒其目的地。<br /> <br />   活动流是一种小规模,也是Java 9中采用的,它定义了具有背压的异步组件之间的交互。例如,作为发布者的数据存储库可以产生数据,作为订阅者的HTTP服务器可以写入响应。活动流的主要目的是允许用户控制发布商产生数据的速度或速度。<br /> <br /> <strong>提示:</strong><br /> 常见的问题:如果发布商不能放慢下去呢?<br /> 活动流的目的只是建立机制和边界。 如果发布商不能放慢速度,那么它必须决定是缓冲还是丢弃还是失败。 <h2>4.Reactive API</h2>   活动流对互操作性起着重要作用。图书馆和基础架构组件感兴趣,但作为应用程序API不太有用,因为它的级别太低。什么应用程序需要更高级别和更丰富的功能API来构成异步逻辑 - 类似于Java 8 Stream API,但不仅仅是集合。这是反应库的作用。<br /> <br />   反应堆是Spring WebFlux选择的活动库。它提供了Mono和Flux API类型,可以通过与运算符的ReactiveX词汇对齐的丰富的运算符来处理0..1和0..N的数据序列。反应堆是一个反应流库,因此所有的运营商都支持非阻塞的背压。反应堆非常重视服务器端的Java。它与Spring紧密合作开发。<br /> <br />   WebFlux要求Reactor作为核心依赖关系,但它可以通过Reactive Streams与其他反应库互操作。作为一般规则,WebFlux API接受普通的Publisher作为输入,在内部适应Reactor类型,使用它们,然后返回Flux或Mono作为输出。所以您可以将任何Publisher作为输入传递,您可以对输出应用操作,但是您需要调整输出以与另一个活动库一起使用。无论何时 - 例如注释控制器,WebFlux透明地适用于使用RxJava或其他反应库。有关详细信息,请参阅反应库。 <h2>5.编程模型</h2> Spring-Web模块包含基于Spring WebFlux - HTTP抽象,Reactive Streams服务器适配器,反应式编解码器和核心Web API的反应性基础,其角色与Servlet API相当,但具有非阻塞语义。<br /> <br /> 在此基础上,Spring WebFlux提供了两种编程模型的选择: <ul> <li>注释控制器 - 与Spring MVC相一致,并且基于与spring-web模块相同的注释。 Spring MVC和WebFlux控制器都支持反应(Reactor,RxJava)返回类型,因此不容易将它们分开。一个显着的区别是,WebFlux还支持反应性@RequestBody参数。</li> <li>功能端点 - 基于lambda的轻量级功能编程模型。将其视为小型库或应用程序可用于路由和处理请求的一组实用程序。注释控制器的巨大差异在于,应用程序负责从开始到结束的请求处理,并通过注释声明意图并被回调。</li> </ul> <h2>6.如何选择一个web框架?</h2>   你应该使用Spring MVC还是WebFlux?我们来看几个不同的观点。<br /> <br />   如果您有一个Spring MVC应用程序工作正常,则不需要更改。命令编程是编写,理解和调试代码的最简单方法。您最多可以选择库,因为历史上绝大多数都是阻止。<br /> <br />   如果您已经购买了一个非阻塞的Web堆栈,Spring WebFlux可以提供与这个空间中的其他人一样的执行模式优势,并且还提供了一些选择的服务器 - Netty,Tomcat,Jetty,Undertow,Servlet 3.1+容器,编程模型 - 注释控制器和功能Web端点,以及可选的反应库 - 反应器,RxJava或其他。<br /> <br />   如果您对使用Java 8 lambdas或Kotlin的轻量级功能Web框架感兴趣,则可以使用Spring WebFlux功能Web端点。对于具有较少复杂要求的较小应用或微服务,这也可能是更好的选择,可以从更大的透明度和控制中受益。<br /> <br />   在微服务架构中,您可以使用Spring MVC或Spring WebFlux控制器或Spring WebFlux功能端点组合应用程序。在两个框架中支持相同的基于注释的编程模型,使得重新使用知识更容易,同时为正确的工作选择正确的工具。<br /> <br />   评估应用程序的一种简单方法是检查其依赖性。如果您使用阻塞持久性API(JPA,JDBC)或网络API,则Spring MVC至少是常见架构的最佳选择。在技​​术上,Reactor和RxJava都可以在单独的线程上执行阻塞调用,但是您不会充分利用非阻塞的Web堆栈。<br /> <br />   如果您有一个Spring MVC应用程序调用远程服务,请尝试反向WebClient。您可以从Spring MVC控制器方法直接返回反应类型(Reactor,RxJava或其他)。每个呼叫的延迟或呼叫之间的相互依赖性越大,益处越大。 Spring MVC控制器也可以调用其他无效组件。<br /> <br />   如果你有一个庞大的团队,记住转向非阻塞,功能和声明性编程的陡峭的学习曲线。在没有完全切换的情况下启动的实际方法是使用反应性WebClient。除了这个开始之外,测量的好处。我们预计,对于广泛的应用,转移是不必要的。<br /> <br />   如果您不确定要查找哪些优点,首先了解非阻塞性I / O的工作原理(例如,单线程Node.js上的并发性不是矛盾)及其影响。标签行是“具有较少硬件的缩放”,但不能保证效果,而不是一些网络I / O可能会变慢或不可预测。这个Netflix博客文章是一个很好的资源。 <h2>7.Spring WebFlux Server的选择</h2>   Netnet,Undertow,Tomcat,Jetty和Servlet 3.1+容器支持Spring WebFlux。 每个服务器都适用于一个通用的Reactive Streams API。 Spring WebFlux编程模型基于该通用API。<br />    <strong>提示:</strong><br /> <em>  常见的问题:Tomcat和Jetty如何在两个堆栈中使用?<br />   Tomcat和Jetty的核心是无阻拦。 这是Servlet API,它添加了一个阻塞的外观。 从版本3.1开始,Servlet API为非阻塞I / O添加了一个选择。 然而,其使用需要注意避免<br />   其他同步和阻塞部件。 因此,Spring的反应式Web堆栈具有低级Servlet适配器来桥接到活动流,但是Servlet API否则不会直接使用。</em><br /> <br />   默认情况下,Spring Boot 2使用Netty WebFlux,因为Netty在异步非阻塞空间中被广泛使用,并且还提供可共享资源的客户端和服务器。 通过比较Servlet 3.1非阻塞I / O没有太多的使用,因为使用它的条数是如此之高。 Spring WebFlux打开了一条实用的通路。<br /> <br />   Spring Boot中的默认服务器选择主要是关于开箱即用的体验。 应用程序仍然可以选择任何其他受支持的服务器,这些服务器也对性能进行了高度优化,完全无阻塞,并适应了反应流反向压力。 在Spring Boot中,进行切换是微不足道的。 <h2>8.性能与规模</h2>   表现有很多特点和意义。 反应和非阻塞通常不会使应用程序运行更快。 在某些情况下,他们可以使用WebClient来并行执行远程调用。 总的来说,需要更多的工作来处理非阻塞的方式,并且可以稍微增加所需的处理时间。<br /> <br />   反应和非阻塞的关键预期好处是能够以小的固定数量的线程和较少的内存进行扩展。 这使得应用程序在负载下更具弹性,因为它们以更可预测的方式扩展。 为了观察这些好处,您需要有一些延迟,包括慢速和不可预测的网络I / O的混合。 这是反应堆栈开始显示其优势的地方,差异可能很大。
  • spring boot 入门之spring session&RESTful APIs

    spring boot 入门之spring session实现restful apis。通过spring boot或者spring mvc整合spring session的方式来实现session的共享达到应用可以水平扩展集群。<h2>一.简介</h2>    spring boot 入门之spring session实现restful apis。通过前面的了解和使用,我们知道可以通过spring boot或者spring mvc整合spring session的方式来实现session的共享达到应用可以水平扩展集群。session默认情况是存了一个cookie在响应的数据里面,然后每次通过cookie来验证session的,但是restful设计中一般不会使用cookie,所以spring session提供了将session id存放在http协议的header中,本文主要讲解如何使用。 <h2>二.编码介绍</h2> <h3>HttpSession & RESTful APIs</h3> 原理:Spring Session 可以允许session在header里面提供来实现RESTful APIs <h3>Spring配置</h3> 在创建一个spring boot项目后,加入相关的依赖。现在我们就可以来进行相关配置。这个配置主要负责创建一个servlet Filter替换原有的HttpSession 使用spring session.主要添加以下spring 相关配置: <pre> <code class="language-java">@Configuration @EnableRedisHttpSession //① public class HttpSessionConfig { @Bean public LettuceConnectionFactory connectionFactory() { return new LettuceConnectionFactory(); //②注意,spring boot项目这里不需要创建一个链接工厂,在application配置文件中配置了相关信息会默认生成一个链接工厂供使用。 } @Bean public HttpSessionStrategy httpSessionStrategy() { return new HeaderHttpSessionStrategy(); //③ } }</code></pre>   ①<code>@EnableRedisHttpSession</code> 注解用来创建一个spring的过滤器类,类的名称为 <code>springSessionRepositoryFilter</code> 这个过滤器用来替换原生的 <code>HttpSession</code> 使用spring session。这个例子中,Spring Session通过Redis来实现存储。<br />   ②创建了一个<code>RedisConnectionFactory</code> 来使Spring Session链接到Redis Server。关于spring data redis相关配置可以参考之前的spring redis整合。(注意,spring boot项目这里不需要创建一个链接工厂,在application配置文件中配置了相关信息会默认生成一个链接工厂供使用。)<br />   ③我们自定义了Spring  Session的HttpSession ,将它整合到了HTTP协议的header里面,替换掉默认的放在cookie中。 <h3>HttpSessionListener 即session监听处理</h3> Spring Session支持<code>HttpSessionListener</code>,通过将<code>SessionDestroyedEvent</code> 和SessionCreatedEvent转换成 <code>HttpSessionEvent</code> 被定义在SessionEventHttpSessionListenerAdapter来实现。需要使用监听,注意以下几点: <ul> <li>确保你所实现的<code>SessionRepository</code> 支持并且配置到启动<code>SessionDestroyedEvent</code> 和SessionCreatedEvent</li> <li>将<code>SessionEventHttpSessionListenerAdapter</code> 配置为spring容器中的一个bean</li> <li>注入每一个<code>HttpSessionListener</code> 到SessionEventHttpSessionListenerAdapter</li> </ul> 如果你使用Redis的方式记录HttpSession,你需要将每一个HttpSessionListener配置为bean。例如,假设你想要支持Spring Security的并发控制,并且需要使用HttpSessionEventPublisher,你可以简单地将HttpSessionEventPublisher添加为一个bean。 在Java配置中,这可能如下所示: <pre> <code class="language-java">@Configuration @EnableRedisHttpSession public class RedisHttpSessionConfig { @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } // ... }</code></pre> 或者xml <pre> <code class="language-xml"><bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/></code></pre>
  • Spring框架Spring IoC容器的核心原理

    Spring框架Spring IoC容器的核心原理,前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一起学习一下Spring IoC的核心原理,正如从历史的角度出发讲述为什么会有Spring一样,希望通过这个切入点能让你轻松的掌握住Spring IoC的核心原理。<h2><br /> 引言</h2> <blockquote> <p><a rel="" target="_blank"href="http://www.leftso.com/blog/335.html" rel="" target="_blank" title="java编程为啥会出现spring框架">java编程为啥会出现spring框架</a><br /> <a rel="" target="_blank"href="http://www.leftso.com/blog/336.html" rel="" target="_blank" title="Spring AOP为何诞生">Spring AOP为何诞生</a><br /> <a rel="" target="_blank"href="http://www.leftso.com/blog/338.html" rel="" target="_blank" title="Spring框架每个版本的特性及历史介绍">Spring框架每个版本的特性及历史介绍</a> </p> </blockquote> <p>前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一起学习一下Spring IoC的核心原理,正如从历史的角度出发讲述为什么会有Spring一样,希望通过这个切入点能让你轻松的掌握住Spring IoC的核心原理。</p> <blockquote> <div> </div> </blockquote> <p>本篇文章假设你已经可以熟练的使用Spring了,因此对于某一个细节如何实现的不会在进行详细的阐述!</p> <h2>二、IoC和DI的基本概念</h2> <p>IoC(控制反转,英文含义:Inverse of Control)是Spring容器的内核,AOP、事务等功能都是建立在此基础上的。从字面意思上可以把IoC拆分为两层含义:<strong>控制和反转</strong>。控制可以理解为是接口实现类的选择权,反转可以理解为这个选择权交给第三方进行管理;总的来说就是某一接口具体实现类的选择控制权从调用类中移除,转交给第三方进行决定,即由Spring容器通过Bean配置来进行控制,这样的话应用程序本身就不用负责依赖对象的创建和维护,而由Spring容器进行管理。</p> <p>尽管我们现在对IoC的基本概念都已经熟读与心了,但是在老一辈的时候,IoC的概念还不是很容易被人理解。在那个年代,业界的一位大佬,软件界泰斗级的人物Martin Fowler提出了DI(Dependency Injection,依赖注入)的概念,来代替IoC。</p> <p>依赖注入的概念和控制反转的概念从本质上是一样的,只是从不同的侧面描述了这个功能。依赖注入的概念描述的是让调用类对某一接口实现类的依赖关系有第三方容器或其他东西注入,以此来移除对某一接口实现类的依赖。</p> <p><img alt="这里写图片描述1" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/98835d648f434ef9b78c9061d9d5fa09.png" title="" /></p> <p>时至今日,我们常说的IoC/DI的时候也是把依赖注入和控制反转作为同一个概念来进行阐述的!</p> <h2><a rel="external nofollow" target="_blank" name="t2"></a>三、从哪里入手IoC容器?</h2> <p>我曾尝试过很多次,想踏进Spring原理的大门,但是一次次都被毫无头绪的开端而打退!后来逐渐翻阅一些书籍逐渐形成了那么一点点思路,接下来主要按着我的思路探讨一下Ioc容器的基本原理。</p> <p>正如我们学习骑自行车一样,开始的时候都是先看别人如何骑的,然后自己才能慢慢的学会(当然发明自行车的人是天才)。学习Spring原理也是一样,只有掌握了基本的Spring的使用,才有可能踏进Spring原理的大门。因此,这里我们从如何使用开始哪?</p> <p>1、首先看一下项目结构</p> <p><img alt="这里写图片描述2" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/67afa4c676734762bcdf1ec05068a98c.png" title="" /></p> <p>继承关系:</p> <p><img alt="这里写图片描述" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/5a0999708616490b9cf94f43f29dcbb5.png" title="" /></p> <p>bean的配置:</p> <p><img alt="这里写图片描述" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/75876548846045d1b49683e15fac4fba.png" title="" /></p> <p>Main代码如下:</p> <p><img alt="这里写图片描述" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/eadd5ccf203944409f0b99d2d456d54e.png" title="" /></p> <p>2、相信每一个学习Spring的小伙伴都是从上述的方式学起的,上图中最显眼的两个类就是红色圈圈出的,也设置我们在最开始使用到的,使用UML工具显示最基本的类图关系:</p> <p><img alt="这里写图片描述6" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/66b540ffabc7457ebd8f4a69d796a85f.png" title="" /></p> <p>庞大的一个继承和实现体系!看到这里大致上也就是我要说的<strong>第二条路线</strong>了(下文会详细介绍)!这条路线向我们展示了从Spring最接近用开发人员使用的<code>ClassPathXmlApplicationContext</code>、<code>FileSystemXmlApplicationContext</code>类到Spring的顶层接口之间层层的继承和实现关系。</p> <p>看到这里我们似乎还是毫无头绪,这就需要我们借鉴前人的经验了,这个经验就是如何正确的理解<code>BeanFactory</code>和<code>ApplicationContext</code>之间的关系。</p> <h2><a rel="external nofollow" target="_blank" name="t3"></a>四、BeanFactory和ApplicationContext之间的关系</h2> <p>我们都知道Spring是通过配置文件、注解、Java类等方式描述Bean与Bean之间的依赖关系,利用Java的反射功能实例化Bean并建立Bean与Bean之间的依赖关系;</p> <p>这些底层的工作正是由Spring IoC容器完成的,除此之外Spring IoC容器还提供了Bean实例缓存、生命周期管理、时间发布等高级服务。</p> <p>而这里要说的<code>BeanFactory</code>和<code>ApplicationContext</code>都作为Spring IoC容器的形态存在,只不过有些许区别而已,简单的来说:(1)BeanFactory接口的实现类是一个<strong>简单容器</strong>系列,该系列的容器只实现了容器最基本的功能;(2)ApplicationContext接口的实现类是一个<strong>高级容器</strong>系列,该系列的容器在简单容器的基础上增加了很多面向框架的特性,对应用环境做了很多适配,同时添加了很多面向应用的功能,例如:国际化支持和框架事件体系结构等。</p> <blockquote> <p>通常情况下,我们习惯称BeanFactory为Ioc容器,而称ApplicationContext为应用上下文,有时候我们还直接称ApplicationContext为Spring容器。</p> </blockquote> <p>至此,我应该可以引出我要说的前两条路线:第一条路线是基于BeanFactory的简单容器系列;第二天路线是基于ApplicationContext的高级容器系列;</p> <h2><a rel="external nofollow" target="_blank" name="t4"></a>五、第一条路线:基于BeanFactory的简单容器系列</h2> <p>既然BeanFactory的实现类也是一个容器,那么我们就应该可以使用它来注入我们的Bean和获取我们的Bean,如何使用哪?请看代码:</p> <p><img alt="这里写图片描述" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/1cbdd66390524ab68f115dacf5c6238d.png" title="" /></p> <blockquote> <p>(1)创建IoC配置文件的抽象资源,这个抽象资源包含了BeanDefinition的定义信息(也就是我们在bean.xml文件中配置的一个bean的数据结构); <br /> (2)创建一个BeanFactory,这里使用的是DefaultListableBeanFactory; <br /> (3)创建一个载入BeanDefinition的读取器,这里使用的是XmlBeanDefinitionReader来载入XML形式的BeanDefinition,通过一个回调配置给BeanFactory; <br /> (4)从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成。</p> </blockquote> <p>上述的过程,完成了整个载入和注册Bean的定义之后,我们所需要的IoC容器就建立起来了,这个时候我们就可以直接使用IoC容器了。</p> <p>上述代码中使用了<code>DefaultListableBeanFactory</code> 这个BeanFactory默认实现的容器完成了Bean的注入和获取操作,查看其继承和实现关系如下:</p> <p><img alt="这里写图片描述" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/07193f8e6fc540a8925b3a37bd91b69a.png" title="" /></p> <p><code>BeanFactory</code>位于接口类结构的顶端,它主要定义了IoC容器中应该具有的基本特性,主要接口定义如下,根据名称就可以看出是什么作用,这里不再一一解释:</p> <p><img alt="这里写图片描述9" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/682fe7d24d9540fbbeac7a4987dba7a3.png" title="" /></p> <p>面对如此多的接口或类,我们应该如何理解哪?举个栗子,就像一辆汽车一样,BeanFactory中定义了这辆汽车应该具有的基本功能,通过层层的接口继承和实现为这个基本的汽车架构定制了很多特性,比如:可以座几个人,是否可以倒车等,一直到最后才形成了一辆基本可以正常使用的汽车,但到这一步还是一个比较粗糙的产品或者半成品。(可以使用,但对于普通用户不会直接使用)</p> <p>而关于这些接口或类的介绍,由于篇幅有限,这里不再一一介绍,主要给大家提供一种思路,如何顺藤摸瓜,掌握第一条理解Spring IoC容器的路线。</p> <p>总的来说,BeanFactory是Spring框架的基础设置,面向的是Spring本身,下文中讲述的第二条路线其中也是使用到了上述代码中的过程,我们在实际的开发中很少会直接使用基于BeanFactory的简单容器系列。</p> <h2><a rel="external nofollow" target="_blank" name="t5"></a>六、第二条路线:基于ApplicationContext的高级容器系列</h2> <p>相对于第一条路线中的汽车半成品来说,第二个路线下的产品才真正算是一辆可以开的出去的汽车,在基于ApplicationContext的高级容器系列下为汽车新增了很多特性,比如:加了电子档位、加了倒车雷达、全景天窗、全液晶显示器什么的,一直到最后才形成了一辆可以使用的汽车(可以使用,普通用户也可以直接使用)。</p> <p><img alt="这里写图片描述10" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/b084800b0a314fb3835b6ca0aef5678b.png" title="" /></p> <p>从上图中可以看出来,相对于BeanFactory来说ApplicationContext增加了很多新特性,例如MessageSource接口、ApplicationEventPublisher接口等,所以说ApplicationContext是一个高级形态意义上的IoC容器。</p> <p>ApplicationContext的主要实现类是<code>ClassPathXmlApplicationContext</code>、<code>FileSystemXmlApplicationContext</code>,前者是通过从类路径加载配置文件,后者模式从文件系统中装载配置。</p> <h2><a rel="external nofollow" target="_blank" name="t6"></a>七、第三条路线:基于WebApplicationContext的Web容器系列</h2> <p>从上边的介绍我们应该已经看出来了,不管是第一条路线还是第二条路线都是基于Java应用的,而我们使用最多的是JavaWeb应用,这也是接下来要说的第三条路线:基于WebApplicationContext的Web容器系列。</p> <p><img alt="这里写图片描述11" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/1c05c71da2e947a19f2c2341488ae1de.png" title="" /></p> <p>WebApplicationContext是专门为Web应用准备的,由于Web应用比一般的Java应用拥有更多的特性,因此WebApplicationContext扩展了ApplicationContext。</p> <p><img alt="这里写图片描述12" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2018-01/bf5cae9e908d49adac61478dd3aae3fc.png" title="" /></p> <p>我们在配置Spring集成Spring MVC的时候基本都会使用上述的方式配置Spring容器,ContextLoaderListener通过Web容器上下文参数<code>contextConfigLocation</code>获取Spring配置文件的位置。如果只是使用Xml配置的Bean的话,会使用WebApplicationContext的实现类XmlWebApplicationContext。</p> <h2><a rel="external nofollow" target="_blank" name="t7"></a>八、总结</h2> <p>本文的目的并不是详细的阐述Spring IoC容器的核心原理,这是因为市面上已经有很多书讲述Spring IoC容器的核心原理的,并且简单的一篇文章很难说清楚这么多的内容,这里主要是是希望通过将Spring IoC容器的核心原理内容进行划分,整理为3条基本路线,这样的话逐步击破,才能使自己不会被庞大的代码结构体系所吓到!</p> <blockquote> <p>纸上得来终觉浅,绝知此事要躬行!</p> </blockquote> <p>对于Spring IoC容器的核心原理远不止这些,但是基本都是在这三条主线上进行穿插,其他没有提到的如:容器初始化,配置文件解析过程、Bean的解析和注册等,希望大家在在进行学习的时候注意到!</p> <p>如果想进一步学习Spring原理的,这里推荐两本书籍《Spring技术内幕-深入解析Spring架构与设计原理》和《精通Spring 4.x 企业应用开发实战》,前者可能有点久,版本不是最新的,但是书中Spring IoC容器和AOP的讲解还是很有参考价值的,后者应该算是市面上一本讲解还算透彻的书籍,值得阅读!</p>
  • Spring AOP为何诞生

    Spring AOP来由,为何会出现Spring AOP这样的框架? 上一篇从Web开发演进过程的一个侧面简述了一下为什么会有Spring框架?事实上只介绍了为什么会有Spring IOC(控制反转/依赖注入)以及Spring IOC的雏形。我们知道Spring的两个核心知识点是:IOC和AOP。因此,这一篇还是以Web开发演进过程为线索继续探讨一下为什么会有Spring AOP?等介绍完这两个核心的知识点之后,才会进一步展开对Spring核心原理的探讨!<h2>引言</h2>     上一篇从Web开发演进过程的一个侧面简述了一下为<a rel="" target="_blank"href="http://www.leftso.com/blog/335.html" rel="" target="_blank">什么会有Spring框架?</a>事实上只介绍了为什么会有Spring IOC(控制反转/依赖注入)以及Spring IOC的雏形。我们知道Spring的两个核心知识点是:IOC和AOP。因此,这一篇还是以Web开发演进过程为线索继续探讨一下为什么会有Spring AOP?等介绍完这两个核心的知识点之后,才会进一步展开对Spring核心原理的探讨!<br />   <h2><strong>一、Web开发演进到一定阶段的痛点</strong></h2> <p>我们在初学习Java Web的时候,应该都经历了以下的阶段:</p> <p>(1)一个主函数main中包含了所有的方法; <br /> (2)将主函数中的方法进行拆分封装,抽取为一个个的方法; <br /> (3)按照每一个方法不同的功能分为一个个的类; <br /> (4)有了MVC模型之后,我们按照MVC的思想将我们的代码拆分为三层,每层负责不同的功能,进行分门别类的管理;</p> <p>很多程序的功能还可以通过继承关系而得到重用,进一步提高了开发效率。再后来,又出现了各种各样的设计模式,使设计程序功能变得得心应手。</p> <p>在面向对象的大环境下,我们可以很好地组织代码,通过继承、封装和多态的思想去设计一个个比较让人满意的类,但是我们慢慢的发现,我们的代码中逐渐多了很多重复性的代码,有人可能会想到,把这些重复性的代码抽取出来不就好了吗?是这样的,我们看一下这种思路的一个实例:<br /> <img alt="操作实例" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-12/77597820f9204bc8892a8c54a39aa026.png" /></p> <p>    可以看到,上述代码功能上确实可以实现,但是我们的业务代码已经被这些非核心的代码所混淆,并且占据了大量的空间!显然这种显示的调用过程成为了我们开发过程中的一个痛点,如何将类似这种的非核心的代码剥离出去成为一个迫切需要解决的问题!</p> <p>    不仅如此,假设我们要控制每一个方法的访问权限,只允许一部分用户进行访问,在不考虑过滤器的情况下,我们是不是需要在每一个方法开始的时候判断用户是否具有该权限,如果有的话就可以进行访问,如果没有的话,就不允许进行访问!</p> <p>    诸如此类,还有数据库事务的控制,数据库连接的创建和关闭等等,这些都充斥这大量重复性的模板代码!一个很现实的问题,假如有一天,业务需求不需要进行日志记录了,那岂不是我们需要把以前写的代码,全部删掉!想想都是一件很可怕的事情!<br /> <br />  </p> <h2><strong>二、使用设计模式进行一次改进</strong></h2> <p>    如果你对设计模式玩的比较熟的话,这个时候你可能会想到使用<strong>JDK动态代理设计模式</strong>(动态代理设计模式可以在原有的方法前后添加判断、选择或其他逻辑)对上述代码进行改进,(关于什么是JDK动态代理,这里不再详细赘述,有不懂的的可以查阅相关资料具体了解一下!)修改后的代码如下:<br /> <img alt="Spring Aop实例代码片段1" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-12/6345b45100d740f5bff96e5bb827c1a7.png" /><br /> 上述为代理类,红色框中圈出的表示以前业务中的模板代码,这里直接输出表示方法执行的过程,以前的UserServiceImpl修改为如下(直接用输出的方式表示方法执行了):<br /> <img alt="Spring Aop实例代码片段2" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-12/4992beb9fe9749bcabc1877a68217a37.png" /><br /> 测试代码如下:<br /> <img alt="Spring Aop实例代码片段3" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-12/c243721d002947199bae526adb3d78d5.png" /><br />  </p> <p>    上述的执行结果可以看出,每次调用一个方法的时候前后都会调用我们期望的代码,实现了我们期望的标准!</p> <p>    通过JDK动态代理的方式,让我们彻底的解放出来了!</p> <h2><strong>三、撕开披在AOP身上的一层薄纱</strong></h2> <p>    上述过程中,我们看到在<strong>动态代理的<code>invoke</code></strong>方法里边,我们相当于在原有方法的调用前后“<strong>植入</strong>”了我们的通用日志记录代码,如果你看到这一层的话,那么恭喜你!你已经领悟到了AOP思想最核心的东西了!</p> <p>    上述抽取公共代码其实就是AOP中<strong>横切</strong>的过程,代理对象中在方法调用前后“<strong>植入</strong>”自己写的通用日志记录代码其实就是AOP中<strong>织入</strong>的过程!这个织入的代码也就是<strong>横切逻辑</strong>,织入代码的过程其实就是在原有的方法前后<strong>增强</strong> 原方法的过程!总的来说,我们想解决我们开发中的痛点,然后就出现了一种技术,这种技术手段就是AOP。</p> <p>AOP书面表述如下:<br /> <br />     AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。<br />  </p> <h2><strong>四、AOP与Spring AOP的关系</strong></h2> <p>    AOP是一种思想,不同的厂商或企业可能有不同的实现方式,为了更好的应用AOP技术,技术专家们成立了AOP联盟来探讨AOP的标准化,AOP联盟定义的AOP体系结构把与AOP相关的概念大致分为由高到低、从使用到实现的三层关系,AOP联盟定义的AOP体系结构如下图:<br /> <img alt="AOP联盟定义的AOP结构图" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-12/0411549085a543a3b156bfff159b1a73.png" /><br />  </p> <p>    在AOP联盟定义的AOP体系结构下有很多的实现者,例如:AspectJ、AspectWerkz、JBoss AOP、Spring AOP等。Spring AOP就是在此标准下产生的,这里不再深入Spring AOP的其他概念,这些概念会在后期探讨。</p> <h2><strong>五、其他问题</strong></h2> <p>    上述通过动态代理的方式实现了简单的AOP,但是值得注意的是,我们的代理目标对象必须实现一个接口,要是一个接口的实现类,这是因为再生成Proxy对象的时候这个方法需要一个目标对象的接口:<br />  </p> <p><img alt="Spring Aop实例代码片段4" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-12/08942f7d864949a996120c9e0cde7037.png" /><br />  </p> <p>    显然,有些特殊的场景使用JDK动态代理技术的话,已经不能够满足我们的场景了,又遇到痛点了!凡事不劳我们操心的Spring框架已经替我们想到了,既然你有这种需求,我就使用一种技术帮你实现就行了,Spring在这里使用CGLib动态代理的方式实现了我们的这种诉求。</p> <p>CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势的织入横切逻辑。</p> <p>    看到这里,我们会想以后会不会还有CGLib解决不了得问题啊?我们已经很清楚的知道了对于Spring AOP来说,使用到了JDK动态代理技术和CGLib动态代理技术,这两种方式已经实现了我们绝大多数的场景,如果还有不能满足的需求,迫切需要解决的痛点,我相信Spring还会采用相应的技术来满足这些场景。</p> <h2><strong>六、总结</strong></h2> <p>    上述的过程,大致从一个侧面探讨了一下我们为什么需要AOP,AOP与Spring AOP的关系以及Spring AOP两种实现的方式(JDK动态代理和CGLib动态代理)。</p> <p>    Spring不尝试提供最为完善的AOP实现,它更侧重于提供一种和Spring IOC容器整个的AOP实现,用于解决实际的问题,在Spring中无缝的整合了Spring AOP、Spring IOC和AspectJ。</p> <p>    当然,Spring AOP的内容不仅仅有这些!例如:我们在使用Spring AOP的时候只是简单的配置了一下(通过XML或注解进行配置),没有像<code>ProxyDemo</code>测试类中的那样,还需要我们手动的调用<code>ProxyFactory</code> 来创建代理对象,然后调用我们的目标方法,其实Spring AOP在内部已经帮我们把这些事情做好了,具体的原理后期会继续探讨。另外,Spring如何整合Spring IOC和AOP的,这一点也会在后期探讨。</p> <p>    最后补充一下!动态代理或者设计模式重要吗?很重要!Spring AOP用到了动态代理,Spring事务管理用到了动态代理,MyBatis数据库连接池用到了动态代理,MyBatis创建Mapper用到了动态代理等等,你说重要不!要想踏进这些高层框架原理的大门,设计模式首先是我们的第一段台阶!</p> <p> </p>
  • spring框架5.0介绍说明/概述

    java编程中spring框架5.0介绍说明/概述,spring5,spring框架,java编程spring框架一直以来都是java编程中流行的框架。 <p>Spring框架5.0介绍说明</p> <h2 style="margin-left:0px; margin-right:0px; text-align:start">1.Spring入门</h2> <div style="text-align:start"> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">本参考指南提供有关Spring框架的详细信息。它为所有功能提供了全面的文档,以及Spring所接受的基本概念(如<em>“依赖注入”</em>)的背景知识。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">如果您刚开始使用Spring,则可能需要通过创建基于Spring Boot的应用程序来开始使用Spring Framework 。Spring Boot提供了一种快速(和有意见的)方式来创建一个基于生产的基于Spring的应用程序。它基于Spring框架,有利于配置的约定,并且旨在尽可能快地让您运行。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">您可以使用start.spring.io生成一个基本项目或遵循的一个“入门”指南类的 入门构建一个RESTful Web服务 之一。除了易于消化以外,这些指南非常<em>重视任务</em>,其中大多数都是基于Spring Boot的。他们还涵盖了Spring解决方案中您可能想要考虑的其他项目。</span></span></span></span></p> </div> </div> <h2 style="margin-left:0px; margin-right:0px; text-align:start">2. Spring框架简介</h2> <div style="text-align:start"> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring Framework是一个Java平台,为开发Java应用程序提供全面的基础设施支持。Spring处理基础设施,以便您可以专注于您的应用程序。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring使您能够从“简单的Java对象”(POJO)构建应用程序,并将企业服务非侵入式应用于POJO。此功能适用于Java SE编程模型以及完整和部分Java EE。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">作为应用程序开发人员,您可以从Spring平台中获益如何:</span></span></span></span></p> </div> <div> <ul style="margin-left:1.5em; margin-right:0px"> <li> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">使Java方法在数据库事务中执行,而不必处理事务API。</span></span></span></span></p> </li> <li> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">使本地Java方法成为HTTP端点,而无需处理Servlet API。</span></span></span></span></p> </li> <li> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">使本地Java方法成为一个消息处理程序,而无需处理JMS API。</span></span></span></span></p> </li> <li> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">使本地Java方法成为管理操作,而无需处理JMX API。</span></span></span></span></p> </li> </ul> </div> </div> <div style="text-align:start"> <h3 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.1。依赖注入和控制反转</span></span></span></h3> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Java应用程序 - 从受限嵌入式应用程序到n层服务器端企业应用程序运行范围的宽松术语通常由协作形成应用程序的对象组成。因此,应用程序中的对象彼此具有<em>依赖关系</em>。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">虽然Java平台提供了丰富的应用程序开发功能,但它缺乏将基本构建块组织成一个连贯的整体的手段,将该任务留给架构师和开发人员。虽然可以使用<em>Factory</em>,<em>Abstract Factory</em>,<em>Builder</em>,<em>Decorator</em>和<em>Service Locator</em>这样的设计模式 来构成组成应用程序的各种类和对象实例,但这些模式只是简单地说明:给出名称的最佳实践,以及什么样的模式,应用于哪里,它解决的问题等等。模式是<em>您必须</em>在应用程序中<em>实现自己的</em>正式的最佳实践。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring框架<em>反转控制</em>(IoC)组件通过提供将不同组件组成完整工作应用程序的正式方法来解决这一问题。Spring Framework将形式化的设计模式作为可以集成到您自己的应用程序中的第一类对象进行编译。许多组织和机构以这种方式使用Spring框架来设计强大的,可<em>维护的</em>应用程序。</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <div style="margin-left:0px; margin-right:0px; text-align:center"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#f1f1f1"><span style="font-family:Montserrat,sans-serif"><span style="color:#0b0a0a">背景</span></span></span></span></span></span></div> <div> <p><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#f1f1f1"><span style="font-family:inherit">“ <em>问题是,控制的哪个方面是(他们)反转?</em> ”Martin Fowler 在2004年在他的网站上提出了有关反转控制(IoC)的 问题 .Fowler建议重新命名原则,使其更加自明,并提出<em>依赖注入</em>。</span></span></span></span></span></p> </div> </div> </div> </div> <div style="text-align:start"> <h3 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2。框架模块</span></span></span></h3> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring框架由组织成约20个模块的功能组成。这些模块分为Core Container,数据访问/集成,Web,AOP(面向对象编程),Instrumentation,Messaging和Test,如下图所示。</span></span></span></span></p> </div> </div> <img alt="spring 框架图" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-07/2937672202ba41c6862b026d169f0528.png" /> <div style="text-align:start"> <div style="margin-left:0px; margin-right:0px"> <div style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="color:#0b0a0a"><span style="font-family:"Varela Round",sans-serif"><em>图1. Spring框架概述</em></span></span></span></span></span></div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">以下部分列出了每个功能的可用模块及其工件名称及其涵盖的主题。工件名称与依赖关系管理工具中使用的<em>工件ID </em>相关。</span></span></span></span></p> </div> <div> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2.1。核心集装箱</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">所述<em>核心容器</em>由以下部分组成<code>spring-core</code>, <code>spring-beans</code>,<code>spring-context</code>,<code>spring-context-support</code>,和<code>spring-expression</code>(弹簧表达式语言)模块。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">的<code>spring-core</code>和<code>spring-beans</code>模块提供框架的基本零件,包括IOC和依赖注入特征。这<code>BeanFactory</code>是工厂模式的复杂实施。它消除了对编程单例的需要,并允许您将依赖关系的配置和规范与实际程序逻辑分离。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">所述<em>上下文</em>(<code>spring-context</code>)模块建立由设置在固体基体上<em>的核心和豆类</em>模块:它是访问一个框架式的方式是类似于一个JNDI注册表对象的装置。上下文模块从Beans模块继承其功能,并增加了对国际化的支持(例如使用资源束),事件传播,资源加载以及例如Servlet容器透明地创建上下文。Context模块还支持Java EE功能,如EJB,JMX和基本远程处理。该<code>ApplicationContext</code>接口是语境模块的焦点。 <code>spring-context-support</code>提供了将常见第三方库集成到Spring应用程序环境中的支持,特别是用于缓存(EhCache,JCache)和调度(CommonJ,Quartz)。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-expression</code>模块提供了强大的<em>表达式语言,</em>用于在运行时查询和操作对象图。它是JSP 2.1规范中规定的统一表达语言(统一EL)的扩展。该语言支持设置和获取属性值,属性分配,方法调用,访问数组,集合和索引器的内容,逻辑和算术运算符,命名变量以及从Spring的IoC容器中的名称检索对象。它还支持列表投影和选择以及通用列表聚合。</span></span></span></span></p> </div> </div> <div> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2.2。AOP和仪器仪表</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-aop</code>模块提供了一个符合<em>AOP</em>联盟标准的面向方面的编程实现,允许您定义方法拦截器和切入点,以便干净地解除实现应分隔的功能的代码。使用源级元数据功能,您还可以将行为信息与.NET属性类似。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">单独的<code>spring-aspects</code>模块提供与AspectJ的集成。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-instrument</code>模块提供了在某些应用服务器中使用的类检测支持和类加载器实现。该<code>spring-instrument-tomcat</code> 模块包含Spring的Tomcat测试代理。</span></span></span></span></p> </div> </div> <div> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2.3。消息</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring框架4包括<code>spring-messaging</code>从关键抽象模块 <em>Spring集成</em>项目,例如<code>Message</code>,<code>MessageChannel</code>,<code>MessageHandler</code>,和其他人作为基于消息的应用奠定了基础。该模块还包括一组用于将消息映射到方法的注释,类似于基于Spring MVC注释的编程模型。</span></span></span></span></p> </div> </div> <div> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2.4。数据访问/集成</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">所述<em>数据访问/集成</em>层由JDBC,ORM,OXM,JMS和交易模块。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-jdbc</code>模块提供了一个JDBC抽象层,无需执行繁琐的JDBC编码和解析数据库供应商特定的错误代码。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-tx</code>模块支持 针对实现特殊接口和<em>所有POJO(普通Java对象)的</em>类的编程和声明式事务管理。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-orm</code>模块为流行的对象关系映射 API(包括JPA和Hibernate)提供集成层 。使用该<code>spring-orm</code>模块,您可以将这些O / R映射框架与Spring提供的所有其他功能结合使用,例如前面提到的简单的声明性事务管理功能。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-oxm</code>模块提供了一个支持Object / XML映射实现的抽象层, 如JAXB,Castor,JiBX和XStream。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-jms</code>模块(Java消息服务)包含用于生成和消费消息的功能。从Spring Framework 4.1开始,它提供了与<code>spring-messaging</code>模块的集成 。</span></span></span></span></p> </div> </div> <div> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2.5。卷筒纸</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">所述<em>网络</em>层由的<code>spring-web</code>,<code>spring-webmvc</code>和<code>spring-websocket</code> 模块。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-web</code>模块提供基本的面向Web的集成功能,例如多部分文件上传功能,以及使用Servlet侦听器和面向Web的应用程序上下文初始化IoC容器。它还包含一个HTTP客户端和Spring的远程支持的Web相关部分。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-webmvc</code>模块(也称为<em>Web-Servlet</em>模块)包含用于Web应用程序的Spring的模型视图控制器(<em>MVC</em>)和REST Web Services实现。Spring的MVC框架提供了领域模型代码和Web表单之间的清晰分离,并与Spring Framework的所有其他功能集成。</span></span></span></span></p> </div> </div> <div> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.2.6。测试</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">该<code>spring-test</code>模块支持使用JUnit或TestNG对Spring组件进行单元测试和 集成测试。它提供了Spring 的一致加载<code>ApplicationContext</code>和这些上下文的缓存。它还提供可用于孤立测试代码的模拟对象。</span></span></span></span></p> </div> </div> </div> <div style="text-align:start"> <h3 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.3。使用场景</span></span></span></h3> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">之前描述的构建模块使Spring成为许多场景中的逻辑选择,从在资源受限设备上运行的嵌入式应用程序到使用Spring的事务管理功能和Web框架集成的全面的企业应用程序。<br /> <img alt="流程" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-07/4ef2d77e2fa6406791ea64ad87b24c68.png" /></span></span></span></span><br />  </p> <div style="margin-left:0px; margin-right:0px; text-align:start"> <div style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="color:#0b0a0a"><span style="font-family:"Varela Round",sans-serif"><em>图2.典型的成熟的Spring Web应用程序</em></span></span></span></span></span></div> </div> <div style="text-align:start"> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring的声明式事务管理功能 使Web应用程序完全事务性,就像使用EJB容器管理的事务一样。所有您的定制业务逻辑都可以使用简单的POJO实现,并由Spring的IoC容器进行管理。其他服务包括支持发送电子邮件和独立于Web层的验证,可让您选择执行验证规则的位置。Spring的ORM支持与JPA和Hibernate集成; 例如,当使用Hibernate时,可以继续使用现有的映射文件和标准的Hibernate <code>SessionFactory</code>配置。表单控制器将Web层与域模型无缝集成,消除了<code>ActionForms</code>将HTTP参数转换为域模型值的需求 或其他类。<br /> <img alt="3" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-07/218014be82624d42ab35c430c91b7b98.png" /></span></span></span></span><br />  </p> <div style="margin-left:0px; margin-right:0px; text-align:start"> <div style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="color:#0b0a0a"><span style="font-family:"Varela Round",sans-serif"><em>图3.使用第三方Web框架的Spring中间层</em></span></span></span></span></span></div> </div> <div style="text-align:start"> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">有时情况不允许您完全切换到不同的框架。Spring框架并<em>没有</em>强迫你在它使用的一切; 这不是一个 <em>全无或缺的</em>解决方案。使用Struts,Tapestry,JSF或其他UI框架构建的现有前端可以与基于Spring的中间层集成,从而允许您使用Spring事务功能。您只需要使用一个连接您的业务逻辑,<code>ApplicationContext</code>并使用它<code>WebApplicationContext</code>来集成您的Web层。<br /> <img alt="4" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-07/48658620eeaf4d7d9defac9736e058f7.png" /></span></span></span></span><br />  </p> <div style="margin-left:0px; margin-right:0px; text-align:start"> <div style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="color:#0b0a0a"><span style="font-family:"Varela Round",sans-serif"><em>图4.远程使用场景</em></span></span></span></span></span></div> </div> <div style="text-align:start"> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">当你需要通过Web服务来访问现有的代码,你可以使用Spring的 <code>Hessian-</code>,<code>Rmi-</code>或<code>HttpInvokerProxyFactoryBean</code>类。启用对现有应用程序的远程访问并不困难。<br /> <img alt="5" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-07/88119b88334c40f7b0178ccc9fa384e3.png" /></span></span></span></span><br />  </p> <div style="margin-left:0px; margin-right:0px; text-align:start"> <div style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="color:#0b0a0a"><span style="font-family:"Varela Round",sans-serif"><em>图5. EJB - 包装现有的POJO</em></span></span></span></span></span></div> </div> <div style="text-align:start"> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring Framework还为Enterprise JavaBeans 提供了一个访问和抽象层,使您能够重用现有的POJO,并将其包装在无状态会话bean中,以用于可能需要声明式安全性的可伸缩的,故障安全的Web应用程序。</span></span></span></span></p> </div> <div style="text-align:start"> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.3.1。依赖管理和命名约定</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">依赖关系管理和依赖注入是不同的。要将Spring的这些不错的功能带入应用程序(如依赖注入),您需要组装所有需要的库(jar文件),并在运行时,并且可能在编译时将它们存入您的类路径。这些依赖关系不是注入的虚拟组件,而是文件系统中的物理资源(通常为)。依赖关系管理的过程包括定位这些资源,存储它们并将其添加到类路径中。依赖关系可以是直接的(例如,我的应用程序依赖于Spring在运行时)或间接(例如我的应用程序取决于<code>commons-dbcp</code>哪个依赖于 <code>commons-pool</code>)。间接依赖关系也被称为“传递性”,它们是最难识别和管理的依赖关系。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">如果要使用Spring,您需要获取构成您所需要的Spring部分的jar库的副本。为了使这更容易,Spring被打包为一组尽可能分离依赖关系的模块,例如,如果您不想编写Web应用程序,则不需要spring-web模块。要参照本指南中,我们使用速记命名约定到Spring库模块<code>spring-*</code>或 <code>spring-*.jar,</code>其中<code>*</code>代表该模块的短名称(例如<code>spring-core</code>,<code>spring-webmvc</code>,<code>spring-jms</code>等)。您使用的实际jar文件名通常是与版本号连接的模块名称(例如<em>spring-core-5.0.0.RC2.jar</em>)。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring Framework的每个版本都会将工件发布到以下位置:</span></span></span></span></p> </div> <div> <ul style="margin-left:1.5em; margin-right:0px"> <li> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Maven Central,它是Maven查询的默认存储库,不需要任何特殊配置。Spring的许多常见的库也可以从Maven Central获得,Spring社区的大部分使用Maven进行依赖关系管理,所以这对他们来说很方便。这里的jar的名字是形式<code>spring-*-<version>.jar</code>,Maven groupId是<code>org.springframework</code>。</span></span></span></span></p> </li> <li> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">在专门用于Spring的公共Maven存储库中。除了最终的GA版本,该存储库还承载开发快照和里程碑。jar文件名与Maven Central格式相同,因此这是一个有用的地方,可以让Spring的开发版本与在Maven Central中部署的其他库一起使用。该存储库还包含捆绑包分发zip文件,其中包含所有Spring jar,捆绑在一起以便于下载。</span></span></span></span></p> </li> </ul> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">所以您需要决定的第一件事是如何管理您的依赖关系:我们通常建议使用自动化系统,如Maven,Gradle或Ivy,但您也可以手动下载所有的jar。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">下面你将会找到Spring工件的列表。有关每个模块的更完整的描述,请参阅框架模块。</span></span></span></span></p> </div> <table class="table table-bordered table-hover"> <caption style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">表1. Spring Framework人工制品</span></span></span></caption> <thead> <tr> <th style="border-color:#dedede; text-align:left; vertical-align:top"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">GroupId的</span></span></span></th> <th style="border-color:#dedede; text-align:left; vertical-align:top"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">的artifactId</span></span></span></th> <th style="border-color:#dedede; text-align:left; vertical-align:top"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">描述</span></span></span></th> </tr> </thead> <tbody> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-aop</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">基于代理的AOP支持</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-aspects</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">基于AspectJ的方面</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-beans</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">豆支持,包括Groovy</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-context</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">应用程序上下文运行时,包括调度和远程抽象</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-context-support</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">支持类将常见的第三方库集成到Spring应用程序上下文中</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-core</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">许多其他Spring模块使用的核心实用程序</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-expression</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">Spring表达语言(Spel)</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-instrument</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">用于JVM自举的仪表代理</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-instrument-tomcat</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">Tomcat的仪表代理</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-jdbc</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">JDBC支持包,包括DataSource设置和JDBC访问支持</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-jms</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">JMS支持包,包括发送/接收JMS消息的帮助类</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-messaging</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">支持消息架构和协议</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-orm</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">对象/关系映射,包括JPA和Hibernate支持</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-oxm</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">对象/ XML映射</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-test</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">支持单元测试和集成测试Spring组件</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-tx</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">交易基础设施,包括DAO支持和JCA整合</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-web</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">基础网络支持,包括Web客户端和基于Web的远程处理</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-webmvc</p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">基于HTTP的Model-View-Controller和REST端点,用于Servlet堆栈</span></span></span></span></span></p> </td> </tr> <tr> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">org.springframework</span></span></span></span></span></p> </td> <td style="background-color:#ffffff; border-color:#dedede"> <p style="text-align:left">spring-websocket</p> </td> <td style="background-color:#ffffff"> <p style="text-align:left"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><span style="color:#34302d">WebSocket和SockJS基础架构,包括STOMP消息传递支持</span></span></span></span></span></p> </td> </tr> </tbody> </table> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">Spring依赖和依靠Spring</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">虽然Spring为大量的企业和其他外部工具提供集成和支持,但它有意将其强制性依赖性保持在绝对最小值:您不必定位和下载(甚至自动)大量的jar库,以便使用Spring用于简单的用例。对于基本的依赖注入,只有一个强制性的外部依赖关系,即日志记录(有关日志记录选项的更详细描述,请参见下文)。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">接下来,我们概述了配置依赖于Spring的应用程序所需的基本步骤,首先是使用Maven,然后使用Gradle,最后使用Ivy。在任何情况下,如果有什么不清楚,请参阅依赖关系管理系统的文档,或查看一些示例代码 - Spring本身在构建时使用Gradle来管理依赖关系,而我们的示例主要使用Gradle或Maven。</span></span></span></span></p> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">Maven依赖管理</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">如果您使用Maven进行依赖关系管理,则甚至不需要显式提供记录依赖关系。例如,要创建应用程序上下文并使用依赖注入来配置应用程序,您的Maven依赖项将如下所示:</span></span></span></span><br />  </p> <pre> <code class="language-xml"><dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.0.RC2</version> <scope>runtime</scope> </dependency> </dependencies></code></pre> </div> </div> </div> </div> </div> </div> </div> </div> <div style="text-align:start"> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">而已。注意,如果您不需要针对Spring API进行编译,那么范围可以被声明为运行时,通常情况下这是基本依赖注入用例的情况。</span></span></span></span></p> </div> <div style="text-align:start"> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">以上示例适用于Maven Central存储库。要使用Spring Maven存储库(例如,用于里程碑或开发人员快照),您需要在Maven配置中指定存储库位置。完整版本:</span></span></span></span><br />  </p> <pre> <code class="language-xml"><repositories> <repository> <id>io.spring.repo.maven.release</id> <url>http://repo.spring.io/release/</url> <snapshots><enabled>false</enabled></snapshots> </repository> </repositories></code></pre> <div style="text-align:start"> <div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">对于里程碑:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><repositories> <repository> <id>io.spring.repo.maven.milestone</id> <url>http://repo.spring.io/milestone/</url> <snapshots><enabled>false</enabled></snapshots> </repository> </repositories></code></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">对于快照:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><repositories> <repository> <id>io.spring.repo.maven.snapshot</id> <url>http://repo.spring.io/snapshot/</url> <snapshots><enabled>true</enabled></snapshots> </repository> </repositories></code></pre> </div> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">Maven“物料清单”依赖</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">当使用Maven时,可能会意外混合不同版本的Spring JAR。例如,您可能会发现第三方库或另一个Spring项目会将旧的版本的依赖关系传递给旧版本。如果您忘记自己明确声明直接依赖,可能会出现各种意外问题。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">为了克服这些问题,Maven支持“物料清单”(BOM)依赖的概念。您可以导入<code>spring-framework-bom</code>您的<code>dependencyManagement</code> 部分,以确保所有弹簧依赖(直接和传递)都是相同的版本。</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>5.0.0.RC2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement></code></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">使用BOM的另一个好处是,您不再需要<code><version></code> 根据Spring Framework工件指定属性:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependencies></code></pre> </div> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">渐进依赖管理</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">要使用具有<a href="http://www.gradle.org/" rel="nofollow" style="box-sizing:border-box; background:transparent; color:#548e2e; text-decoration:underline; line-height:inherit" target="_blank">Gradle</a>构建系统的Spring存储库,请在该<code>repositories</code>部分中包含相应的URL :</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#f5f5f5"><span style="font-family:Monaco,Menlo,Consolas,"Courier New",monospace"><span style="color:rgba(0, 0, 0, 0.9)"><code>repositories { mavenCentral() <span style="color:#999988"><em>// and optionally...</em></span> maven { url <span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">http://repo.spring.io/release</span><span style="color:#dd1144">"</span></span> } }</code></span></span></span></span></span></span></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">您可以更改<code>repositories</code>从URL <code>/release</code>到<code>/milestone</code>或<code>/snapshot</code>适当。一旦存储库被配置,你可以按照通常的Gradle方式声明依赖:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#f5f5f5"><span style="font-family:Monaco,Menlo,Consolas,"Courier New",monospace"><span style="color:rgba(0, 0, 0, 0.9)"><code>dependencies { compile(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">org.springframework:spring-context:5.0.0.RC2</span><span style="color:#dd1144">"</span></span>) testCompile(<span style="color:#dd2200"><span style="color:#dd1144">"</span><span style="color:#dd1144">org.springframework:spring-test:5.0.0.RC2</span><span style="color:#dd1144">"</span></span>) }</code></span></span></span></span></span></span></pre> </div> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">常春藤依赖管理</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">如果您喜欢使用<a href="https://ant.apache.org/ivy" rel="nofollow" style="box-sizing:border-box; background:transparent; color:#548e2e; text-decoration:underline; line-height:inherit" target="_blank">Ivy</a>来管理依赖项,那么还有类似的配置选项。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">要配置Ivy以指向Spring存储库,请将以下解析器添加到 <code>ivysettings.xml</code>:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><resolvers> <ibiblio name="io.spring.repo.maven.release" m2compatible="true" root="http://repo.spring.io/release/"/> </resolvers></code></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">您可以更改<code>root</code>从URL <code>/release/</code>到<code>/milestone/</code>或<code>/snapshot/</code>适当。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">配置完成后,您可以按通常的方式添加依赖项。例如(in <code>ivy.xml</code>):</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code><dependency org="org.springframework" name="spring-core" rev="5.0.0.RC2" conf="compile->runtime"/>xx</code></pre> </div> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">分发Zip文件</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">虽然使用支持依赖关系管理的构建系统是推荐的获取Spring框架的方法,但仍然可以下载分发zip文件。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">分发的拉链发布到Spring Maven Repository(这只是为了方便起见,您不需要Maven或任何其他构建系统才能下载它们)。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">要下载一个分发zip打开一个Web浏览器到 http://repo.spring.io/release/org/springframework/spring,并为所需的版本选择相应的子文件夹。分发文件结束<code>-dist.zip</code>,例如spring-framework- {spring-version} -RELEASE-dist.zip。发行的分发也是针对里程碑和 快照发布的。</span></span></span></span></p> </div> </div> </div> <div style="text-align:start"> <h4 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">2.3.2。记录</span></span></span></h4> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring的日志记录设置已经修改为Spring 5:它仍然基于Apache Commons Logging API,也称为Jakarta Commons Logging(JCL)。但是,现在<code>spring-core</code> 指的是<code>spring-jcl</code>模块中定制的Commons Logging桥,具有Spring特定的<code>LogFactory</code>实现,它自动地连接到 Log4j 2,SLF4J或JDK自己的<code>java.util.logging</code>(JUL)。该实现类似于JCL-over-SLF4J桥,但具有一系列动态检测的提供程序,类似于JBoss Logging的常见目标(如Hibernate和Undertow所支持的)。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">作为一个好处,不再需要像JCL-over-SLF4J这样的外部桥接器,相应地不需要从<code>spring-core</code>依赖关系手动排除标准Commons Logging jar 。相反,它只是在运行时在Spring的自动检测样式中工作:只需将Log4j 2.x或SLF4J放在您的类路径上,而不需要任何额外的桥接jar,或者依靠通过JUL(具有可自定义的JUL设置)的默认日志记录。并且很好地对齐,默认的Hibernate设置将选择相同的通用日志目标。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">如果Log4j和SLF4J都存在,则Log4j API将被优选使用(因为它直接匹配JCL的签名,并且本机支持“致命”日志级别以及延迟解析的消息对象),类似于JBoss Logging的提供程序首选项。可以将Log4j配置为委派给SLF4J,否则SLF4J可能被配置为委托给Log4j:请检查其网站上的说明,了解如何在这种混合场景中达成一致的结果。</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <table class="table table-bordered table-hover"> <tbody> <tr> <td style="background-color:none; text-align:center; width:80px"> </td> <td style="background-color:none"> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#ebf1e7"><span style="color:rgba(0, 0, 0, 0.6)"><span style="font-family:inherit">从Spring 5起,删除对外部Commons Logging网桥的任何引用,还可以从现有的<code>spring-core</code> 依赖关系设置中任意手动排除标准Commons Logging jar 。您的Log4j或SLF4J或JUL设置将继续工作,无需更改。请注意,您可能仍然需要<code>commons-logging</code>其他库(例如Apache HttpClient,Castor,HtmlUnit)的排除,以便代替Spring的JCL桥接器。</span></span></span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#ebf1e7"><span style="color:rgba(0, 0, 0, 0.6)"><span style="font-family:inherit"><code>LogFactory</code>Commons Logging级别的自定义实现将不会被拾取,因为Spring的Bridge不支持定制的commons-logging.properties设置。对于任何其他日志提供程序,请设置相应的SLF4J或JUL桥(您很可能需要其他库,如Hibernate)。请注意,Log4j 1.x已经达到其使用寿命; 请迁移到Log4j 2.x.</span></span></span></span></span></span></p> </div> <div> <p><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="background-color:#ebf1e7"><span style="color:rgba(0, 0, 0, 0.6)"><span style="font-family:inherit">如果您遇到Spring Commons Logging实现的任何其他问题,请考虑排除<code>spring-jcl</code>和切换到标准<code>commons-logging</code>工件(支持<code>commons-logging.properties' setup) or to `jcl-over-slf4j</code>。</span></span></span></span></span></span></p> </div> </td> </tr> </tbody> </table> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">使用Log4j 2.x</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Log4j 2本身就是将原来的Log4j项目(1.x现在是EOL)重新进行重写。从Spring 5开始,嵌入式日志桥将在类路径上可用时自动委托给Log4j 2.x。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">因此,要使用Log4j与Spring,所有你需要做的就是把Log4j的在类路径,并为其提供一个配置文件(<code>log4j2.xml</code>,<code>log4j2.properties</code>或其他 支持的配置格式)。对于Maven用户,所需的最小依赖是:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.2</version> </dependency> </dependencies></code></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">如果您还希望启用SLF4J委托Log4j,例如默认使用SLF4J的其他库,则还需要以下依赖关系:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.8.2</version> </dependency> </dependencies></code></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">以下是<code>log4j2.xml</code>登录控制台的示例:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="org.springframework.beans.factory" level="DEBUG"/> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration></code></pre> </div> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">使用SLF4J与Logback</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Java的简单日志门面(SLF4J)是Spring通常使用的其他库使用的流行API。它通常与Logback一起使用, 它是SLF4J API的本机实现,因此在添加到应用程序类路径时由Spring自动检测:</span></span></span></span></p> </div> <div style="margin-left:0px; margin-right:0px"> <div> <pre> <code class="language-xml"><dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.2</version> </dependency> </dependencies></code></pre> </div> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">或者,您还可以将SLF4J配置为委托给Log4j(见上文)或JUL,特别是对于默认使用SLF4J的其他库。请注意,所有图书馆通过同一个日志门面并不重要; 这只是重要的,他们最终委托给同一个日志提供商。所以当Spring可以直接去Log4j时,其他库可能会通过Log4j的SLF4J绑定,或类似于JUL。</span></span></span></span></p> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">使用JUL(java.util.logging)</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit"><code>java.util.logging</code>如果类路径中没有检测到Log4j或SLF4J API,Spring将默认委派。所以没有特殊的依赖关系:只要<code>java.util.logging</code>在独立的应用程序(在JDK级别使用自定义或默认的JUL设置)或应用程序服务器的日志系统(和它的系统范围的JUL设置)。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">请注意,该<code>java.logging</code>模块在JDK 9中默认不存在,因为它不包括在内<code>java.base</code>。当使用Spring与Log4j或SLF4J时,这可以正常工作,因为在这种情况下不引用JUL API。但是,当选择使用JUL作为默认日志提供程序时,请记住激活该<code>java.logging</code>模块。</span></span></span></span></p> </div> </div> <div> <h5 style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff">Commons登录WebSphere</span></span></span></h5> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">Spring应用程序可以在本身提供JCL实现的容器上运行,例如IBM的WebSphere Application Server(WAS)。这不会引起问题本身,而是导致需要了解的两种不同的场景:</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">在“父第一”ClassLoader委托模型(WAS中的默认值)中,应用程序将始终选择Commons Logging提供的服务器版本,委托给WAS记录子系统(实际上基于JUL)。JCL的应用程序提供的变体,无论是Spring 5还是JCL-over-SLF4J桥,将随着任何本地包含的日志提供程序而被有效地忽略。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">使用“父进程”委托模式(常规Servlet容器中的默认值,但WAS上的显式配置选项),将提取应用程序提供的Commons Logging变体,使您能够设置本地包含的日志提供程序,例如Log4j或Logback,在您的应用程序。在没有本地日志提供程序的情况下,Spring(如常规Commons Logging)将默认委托给JUL,有效地记录到WebSphere的日志记录子系统,如“父第一”方案。</span></span></span></span></p> </div> <div> <p style="margin-left:0px; margin-right:0px"><span style="color:#34302d"><span style="font-family:"Varela Round",sans-serif"><span style="background-color:#ffffff"><span style="font-family:inherit">总而言之,我们建议您将“Spring”应用程序部署在“最后一个”模式中,因为它自然允许本地提供程序以及服务器的日志子系统。</span></span></span></span></p> </div> </div> </div> </div>
  • Spring Boot 2.0 中的Spring Boot Actuator变化

    Spring Boot 2.0,Spring框架的Spring Boot 中的Spring Boot Actuator变化讲解。并且了解如何在Spring Boot 2.0中使用Actuator端点,包括创建自定义端点和使用健康指示器。Spring Boot 2.0 中的Spring Boot Actuator变化
  • spring boot 入门之整合spring session实现session共享

    spring boot 入门之整合spring session实现session共享。一直以来Java编程中web项目中的session共享问题都是一个很难解决的问题。接下来将讲解通过spring boot整合spring session的方案,将session存入分布式缓存Redis中实现session的共享。<h2>一.前言</h2>   spring boot 入门之整合spring session实现session共享。一直以来Javaweb项目中的session共享问题都是一个很难解决的问题。原因是session是由启动servlet的当前web容器所创建和管理。与其他地方的web容器很难通讯。导致无法共享也就很难实现集群化。这里将通过spring boot整合spring session的方案,将session存入分布式缓存Redis中实现session的共享。 <h2>二.编码</h2> <strong>pom.xml文件:</strong> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project</groupId> <artifactId>demo-springboot-spring-session</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>demo-springboot-spring-session</name> <description>lee-leftso-v2.0</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> 核心配置类,HttpSessionConfig: <pre> <code class="language-java">package net.xqlee.project.config; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; /** 启用redis session **/ /*** * * @author xqlee maxInactiveIntervalInSeconds设置session超时时间,默认1800秒 */ @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class HttpSessionConfig { // spring boot项目可以直接配置application配置文件自动注册redis connect 工厂 // 非boot项目则需要再这里配置一下redis得链接工厂 } </code></pre> <strong>编写一个测试的controller,TestController:</strong> <pre> <code class="language-java">package net.xqlee.project.controller; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("/test.do") public Object testSession(HttpServletRequest request) { Map<String, Object> obj = new HashMap<>(); obj.put("result", true); request.getSession().setAttribute("time", new Date().getTime()); obj.put("time", request.getSession().getAttribute("time")); return obj; } } </code></pre> <p><strong>application配置文件配置redis的链接信息</strong></p> <pre> <code class="language-html">spring.redis.host=10.1.1.2 spring.redis.password= spring.redis.port=6379 </code></pre> <p><span style="color:#0066cc"><strong>具体的redis配置信息根据自己的环境改变</strong></span></p> <h2>三.测试</h2> 启动spring boot项目,注意观察启动日志<br /> <img alt="启动日志" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/5c72b8f1caff4859b11a60a590bbbf2c.png" /><br /> 从上方日志可以看到springSessionRepositoryFilter已经启用<br /> <br /> 在浏览器中访问测试controller的地址test.do<br /> 通过谷歌浏览器的调试模式可以看到SESSION的cookie<br /> <img alt="cookie" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/a39e346b5dca4a1493812e9c15793ed4.png" /><br /> 再通过redis的可视化链接工具链接过去查看:<br /> <img alt="session redis" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-11/6f5d096243ea4d4d85d53bd83105efa6.png" /><br /> 上图可以看到: <ul> <li>session id和浏览器中的对应;</li> <li>自己添加的time属性;</li> </ul> 到这里spring  boot 整合spring session 通过redis的方式持久化完成。<br /> <br />  
  • spring boot 整合redis实现spring的缓存框架

    spring boot 1.5整合redis实现spring的缓存框架,spring boot,redisspring boot 整合redis实现spring的缓存框架<br /> <br /> 1.创建一个spring boot项目<br /> <img alt="项目" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-05/87917c2a16564cc08bf8e7670ec943ea.jpg" /><br /> 2.配置pom.xml文件 <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.leftso</groupId> <artifactId>demo-springboot-redis</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-springboot-redis</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> <br /> 3.在spring boot的application配置文件中配置redis的相关信息 <pre> <code>####################Redis 配置信息 ########################## # Redis数据库分片索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=10.1.1.134 # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=-1 # 连接池中的最大空闲连接 spring.redis.pool.max-idle=8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle=0 # 连接超时时间(毫秒) spring.redis.timeout=0</code></pre> <br /> 4.配置redis整合入spring的缓存框架 <pre> <code class="language-java">package com.leftso.config; import java.lang.reflect.Method; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; @Configuration @EnableCaching // 继承CachingConfigurerSupport并重写方法,配合该注解实现spring缓存框架的启用 public class RedisConfig extends CachingConfigurerSupport { /** 载入通过配置文件配置的连接工场 **/ @Autowired RedisConnectionFactory redisConnectionFactory; @SuppressWarnings("rawtypes") @Autowired RedisTemplate redisTemplate; @Bean RedisTemplate<String, Object> objRedisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } /* * (non-Javadoc) * * @see org.springframework.cache.annotation.CachingConfigurerSupport# * cacheManager() */ @Bean // 必须添加此注解 @Override public CacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate); // 设置缓存过期时间 // redisCacheManager.setDefaultExpiration(60);//秒 return redisCacheManager; } /** * 重写缓存的key生成策略,可根据自身业务需要进行自己的配置生成条件 * * @see org.springframework.cache.annotation.CachingConfigurerSupport# * keyGenerator() */ @Bean // 必须项 @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } } </code></pre> <br /> 5.创建一个测试的pojo和一个测试的controller <pre> <code class="language-java">package com.leftso.pojo; import java.io.Serializable; /** * * <pre> * [Summary] * 测试用简单类型 * [Detail] * TODO * [Author] * XQLEE * [Version] * v1.0 * 2017年5月8日上午9:58:42 * </pre> */ public class Address implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String id; private String city; private String detail; public Address() { } public Address(String id, String city, String detail) { super(); this.id = id; this.city = city; this.detail = detail; } /** * @return the id */ public String getId() { return id; } /** * @param id * the id to set */ public void setId(String id) { this.id = id; } /** * @return the city */ public String getCity() { return city; } /** * @param city * the city to set */ public void setCity(String city) { this.city = city; } /** * @return the detail */ public String getDetail() { return detail; } /** * @param detail * the detail to set */ public void setDetail(String detail) { this.detail = detail; } } </code></pre>   <pre> <code class="language-java">package com.leftso.controller; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.leftso.pojo.Address; @RestController public class CacheTestCtrl { @GetMapping("/getAddr") @Cacheable(value = "address-cache") // 设置缓存的名称,也可以通过key属性指定缓存的key,keyGenerator指定key生成策略器(keyGenerator一般推荐在重写CachingConfigurerSupport类里面的方法适合全局指定) public Address getAddress() { Address addr = new Address("001", "重庆市", "渝北区"); System.out.println("==========你看见这句话表示没有缓存时候打印出来的========"); return addr; } } </code></pre> <br /> 6.启动spring boot项目,访问地址localhost:8080/getAddr<br /> 第一次访问将会在控制台中看到以下输出:<br /> <img alt="1" class="img-thumbnail" src="/assets/upload/blog/thumbnail/2017-05/8273e3645def48cfb209a482857ff0ab.jpg" /><br /> <br /> 后面多次刷新都不会进入到该方法中去读取信息,而是通过缓存直接读取了缓存信息。<br /> <br /> <br /> 至此spring boot整合redis 实现基本的缓存已经完成。