个人看法:设计依赖查找的设计模式,是为了解耦.
单一类型依赖查找
- JNDI javax.naming.Context#lookup
- JavaBeans java.beans.beancontext.BeanContext
集合类型依赖查找
- java.beans.beancontext.BeanContext#getCurrentServiceSelectors
- 层析性依赖查找
Springboot中使用JNDI
JNDI即Java Naming and Directory Interface(JAVA命名和目录接口),那么java命名目的就是为了记录一些不方便记录的内容,就像人的名字或DNS中的域名与IP的关系。
两种模式
- Springboot Embedded Tomcat(嵌入Tomcat)使用JNDI
- Springboot WAR 使用JNDI
1. Springboot Embedded Tomcat(嵌入Tomcat)使用JNDI
- 启用默认禁用的JNDI命名。
- 构建一个ContextResource对象,然后添加到Context对象中
java:/comp/env/ 固定写法
JndiConfig.java
package com.rumenz;import org.apache.catalina.Context;import org.apache.catalina.startup.Tomcat;import org.apache.tomcat.util.descriptor.web.ContextResource;import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;import org.springframework.boot.web.servlet.server.ServletWebServerFactory;import org.springframework.context.annotation.Bean;import org.springframework.jndi.JndiObjectFactoryBean;import org.springframework.stereotype.Component;import javax.naming.NamingException;import javax.sql.DataSource;@Componentpublic class JndiConfig { @Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcatServletWebServerFactory = new TomcatServletWebServerFactory() { @Override protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { tomcat.enableNaming(); //启用默认禁用的JNDI命名 return super.getTomcatWebServer(tomcat); } //数据库配置信息可以配置在文件中,数据库发生变动,只需修改配置文件,而不用修改代码. @Override protected void postProcessContext(Context context) { ContextResource resource = new ContextResource(); resource.setName("jdbcMydb"); resource.setType(DataSource.class.getName()); resource.setProperty("driverClassName", "com.mysql.jdbc.Driver"); resource.setProperty("url", "jdbc:mysql://127.0.0.1:3306/test"); resource.setProperty("username", "root"); resource.setProperty("password","root1234"); context.getNamingResources().addResource(resource); } }; return tomcatServletWebServerFactory; } @Bean public DataSource jndiDataSource() throws IllegalArgumentException, NamingException { JndiObjectFactoryBean bean = new JndiObjectFactoryBean(); // create JNDI data source bean.setJndiName("java:/comp/env/jdbcMydb"); // jndiDataSource is name of JNDI data source bean.setProxyInterface(DataSource.class); bean.setLookupOnStartup(true); bean.afterPropertiesSet(); return (DataSource) bean.getObject(); }}
MysqlTest.java
package com.rumenz;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.boot.CommandLineRunner;import org.springframework.context.ApplicationContext;import org.springframework.stereotype.Component;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.sql.DataSource;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;@Componentpublic class MysqlTest implements ApplicationRunner { public static DataSource dataSource = null; static { Context context = null; try { context = new InitialContext(); } catch (NamingException e) { e.printStackTrace(); } //根据资源名称搜索 try { dataSource = (DataSource)context.lookup("java:/comp/env/jdbcMydb"); } catch (NamingException e) { e.printStackTrace(); } System.out.println("static-----"); } public void run(ApplicationArguments args) throws Exception { System.out.println("run---------"); Statement stmt = null; try { Connection conn = dataSource.getConnection(); //查询 stmt = conn.createStatement(); String sql = "SELECT id,name FROM qq limit 1"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); System.out.print("id: " + id); System.out.println(", name: " + name); } rs.close(); stmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); } }}
源码:https://github.com/mifunc/spr...
2.Springboot WAR 使用JNDI
打包成war包放到tomcat,需要修改tomcat/conf/context.xml和tomcat/conf/server.xml
tomcat/conf/context.xml
<ResourceLink name="jdbcMydb" global="jdbcMydb" auth="Container" type="javax.sql.DataSource" />
tomcat/conf/server.xml
<Resource name="jdbcMydb" global="jdbcMydb" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/test" username="root" password="root1234" maxActive="100" maxIdle="20" minIdle="5" maxWait="10000"/>
业务代码
JNDIController.java
package com.rumenz.controller;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import javax.sql.DataSource;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class JNDIController { @Autowired private DataSource dataSource; @GetMapping("/test") public String test() { try { Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement(); String sql = "SELECT id,name FROM qq limit 1"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); System.out.print("id: " + id); System.out.println(", name: " + name); } rs.close(); stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } return null; }}
源码:https://github.com/mifunc/Spr...
java.beans.beancontext.BeanContext(单一类型依赖查找/集合类型依赖查找)
单一类型依赖查找
- java.beans.beancontext.BeanContextServicesSupport#getService
集合类型依赖查找
- java.beans.beancontext.BeanContextServicesSupport#getCurrentServiceSelectors
层析性依赖查找
多个BeanContext相互为父子关系. 一个service的依赖有可能在多个BeanContext