一、依赖注入的三种方式
在实际环境中实现IoC容器的方式主要分为两大类,一类是依赖查找,依赖查找是通过资源定位,把对应的资源查找回来。另一类则是依赖注入。
一般而言,依赖注入可分为3中方式:
- 构造器注入
- setter注入
- 接口注入
构造器注入和setter注入是主要的注入方式,而接口注入是从别的地方注入的方式,比如,在Web工程中,配置的数据源往往是通过服务器(比如tomcat)
去配置的,这个时候可以用JNDI(Java Naming and Directory interface)的形式通过接口将它注入Spring IoC容器中来,下面就是对它们进行详解。
1、构造器注入
构造器注入依赖于构造方法实现,而构造方法是可以是有参构造或无参构造。在大部分情况下,我们都是通过类的构造方法来创建类的对象,Spring也可以采用反射的方式,
通过使用构造方法完成注入,这就是构造器注入的原理。
为了让Spring完成对应的构造注入,我们由必要取描述具体的类,构造方法并设置对应的参数,这样Spring就会通过对应的信息用反射的形式创建对象。
2、使用setter注入
setter注入是Spring中最主流的注入方式,它利用Java Bean规范所定义的setter方法来完成注入,灵活且可读性高。它消除了使用构造器注入时出现多个参数的可能性,
首先可以把构造方法声明为无参构造,然后使用setter注入为其设置对应的值,其实也是通过Java反射技术得以实现的。
3、接口注入
有时候资源并不是来至自身系统,而是来至外界,比如数据库连接资源完全可以在tomcat下配置,单后通过JNDI的形式去获取它,这样数据库连接资源是属于开发工程外的资源,这个时候我们
可以采用接口注入的形式来获取它,比如在tomcat中可以配置参数数据源,又如在Eclipse中配置了tomcat后,可以打开服务器的context.xml文件。
二、三种注入方式的测试案例
总的配置文件:applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans
3 xmlns="http://www.springframework.org/schema/beans"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans
6 http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
7 <!-- 依赖注入·构造器注入 -->
8 <bean id="user_xfwl" class="com.xfwl.spring.DI.UserBean">
9 <constructor-arg index="0" value="小风微凉"/>
10 <constructor-arg index="1" value="123456"/>
11 </bean>
12 <!-- 依赖注入·setter注入 -->
13 <bean id="admin_xfwl" class="com.xfwl.spring.DI.Administrators">
14 <property name="aid" value="100001"></property>
15 <property name="aname" value="小风微凉"></property>
16 <property name="apwd" value="123456"></property>
17 </bean>
18 <bean id="dao" class="com.xfwl.spring.DI.DAO">
19 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
20 <property name="url" value="jdbc:oracle:thin:@***.36.17.**:1521:***"/>
21 <property name="username" value="***"/>
22 <property name="password" value="***"/>
23 </bean>
24 <bean id="daoImpl" class="com.xfwl.spring.DI.LoginDaoImp">
25 <property name="dao" ref="dao"/>
26 </bean>
27
28 <!-- 依赖注入·接口注入 -->
29 <!-- 配置数据源,使用C3P0连接池 的接口注入实现-->
30 <bean name="dataSource"
31 class="com.mchange.v2.c3p0.ComboPooledDataSource">
32 <property name="driverClass" value="${jdbc.driverClass}"></property>
33 <property name="jdbcUrl" value="${jdbc.url}"></property>
34 <property name="user" value="${jdbc.username}"></property>
35 <property name="password" value="${jdbc.password}"></property>
36 <!-- 指定连接池中保留的[最大连接数]. Default:15-->
37 <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
38 <!-- 指定连接池中保留的[最小连接数]-->
39 <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
40 <!-- 指定连接池的初[始化连接数] 取值应在minPoolSize 与 maxPoolSize 之间.Default:3-->
41 <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
42 <!-- [最大空闲时间],60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0-->
43 <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
44 <!-- 当连接池中的连接耗尽的时候c3p0[一次同时获取的连接数]. Default:3-->
45 <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
46 <!--
47 JDBC的标准,用以控制数据源内加载的PreparedStatements数量。
48 但由于预缓存的statements属于单个connection而不是整个连接池所以设置这个参数需要考虑到多方面的因数.
49 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0
50 -->
51 <property name="maxStatements" value="${jdbc.maxStatements}"/>
52 <!-- 每60秒检查所有连接池中的[空闲连接].Default:0 -->
53 <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
54 </bean>
55 </beans>
1、构造器注入
1 package com.xfwl.spring.DI;
2 /**
3 * 测试依赖注入-构造器注入
4 * @function
5 * @author 小风微凉
6 * @time 2018-7-10 下午2:17:16
7 */
8 public class UserBean {
9 private String uname;
10 private String upwd;
11 //无参构造
12 public UserBean(){}
13 //有参构造
14 public UserBean(String uname,String upwd){
15 this.uname=uname;
16 this.upwd=upwd;
17 }
18 public String getUname() {
19 return uname;
20 }
21 public void setUname(String uname) {
22 this.uname = uname;
23 }
24 public String getUpwd() {
25 return upwd;
26 }
27 public void setUpwd(String upwd) {
28 this.upwd = upwd;
29 }
30 @Override
31 public String toString() {
32 return "UserBean [uname=" + uname + ", upwd=" + upwd + "]";
33 }
34 }
配置文件:
1 <!-- 依赖注入·构造器注入 -->
2 <bean id="user_xfwl" class="com.xfwl.spring.DI.UserBean">
3 <constructor-arg index="0" value="小风微凉"/>
4 <constructor-arg index="1" value="123456"/>
5 </bean>
2、使用setter注入
1 package com.xfwl.spring.DI;
2 /**
3 * 依赖注入·setter注入
4 * @function
5 * @author 小风微凉
6 * @time 2018-7-10 下午2:37:54
7 */
8 public class Administrators {
9 private String aid;
10 private String aname;
11 private String apwd;
12
13 public Administrators(){}
14
15 public String getAid() {
16 return aid;
17 }
18
19 public void setAid(String aid) {
20 this.aid = aid;
21 }
22
23 public String getAname() {
24 return aname;
25 }
26
27 public void setAname(String aname) {
28 this.aname = aname;
29 }
30
31 public String getApwd() {
32 return apwd;
33 }
34
35 public void setApwd(String apwd) {
36 this.apwd = apwd;
37 }
38
39 @Override
40 public String toString() {
41 return "Administrators [aid=" + aid + ", aname=" + aname + ", apwd="
42 + apwd + "]";
43 }
44
45 }
测试使用setter注入连接数据库,实现一次查询
创建一个DAO.java
1 package com.xfwl.spring.DI;
2
3 import java.sql.Connection;
4 import java.sql.Driver;
5 import java.sql.DriverManager;
6 import java.sql.SQLException;
7
8 /**
9 * 登录连接DAO
10 * @function
11 * @author 小风微凉
12 * @time 2018-7-10 下午3:21:43
13 */
14 public class DAO {
15 private String driverClassName;
16 private String url;
17 private String username;
18 private String password;
19 /**
20 * 获取数据库连接
21 * @param driverClassName
22 */
23 public Connection getConn(){
24 Connection con=null;
25 try{
26 //加载Oracle的驱动类
27 Class.forName(driverClassName) ;
28 con =DriverManager.getConnection(url , username , password ) ;
29 }catch(SQLException ex){
30 System.out.println("数据库连接失败!");
31 ex.printStackTrace() ;
32 } catch (ClassNotFoundException e) {
33
34 System.out.println("数据库连接失败!");
35 e.printStackTrace() ;
36 }
37 return con;
38 }
39 /**
40 * 释放数据库连接
41 * @param driverClassName
42 */
43 public void releaseConn(Connection conn){
44 try {
45 if(!conn.isClosed()){
46 conn.close();
47 }
48 } catch (SQLException e) {
49 e.printStackTrace();
50 }
51 }
52 public void setDriverClassName(String driverClassName) {
53 this.driverClassName = driverClassName;
54 }
55 public void setUrl(String url) {
56 this.url = url;
57 }
58 public void setUsername(String username) {
59 this.username = username;
60 }
61 public void setPassword(String password) {
62 this.password = password;
63 }
64 }
创建一个LoginDaoImp.java
1 package com.xfwl.spring.DI;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7
8 /**
9 * 登录DAO
10 * @function
11 * @author 小风微凉
12 * @time 2018-7-10 下午3:21:43
13 */
14 public class LoginDaoImp {
15 private DAO dao;
16 public void queryCstListByNo(String cstNo) throws SQLException{
17 Connection conn=dao.getConn();
18 String sql="SELECT CIF_CSTNO,CIF_HOSTNO,CIF_NAMECN FROM CB_CST_INF WHERE CIF_CSTNO=?";
19 PreparedStatement pst=conn.prepareStatement(sql);
20 pst.setString(1, cstNo);
21 ResultSet result=pst.executeQuery();
22 while(result.next()){
23 System.out.println("企业客户号:"+result.getString("CIF_CSTNO"));
24 System.out.println("核心客户号:"+result.getString("CIF_HOSTNO"));
25 System.out.println("客户名称:"+result.getString("CIF_HOSTNO"));
26 }
27 dao.releaseConn(conn);
28 }
29 public DAO getDao() {
30 return dao;
31 }
32 public void setDao(DAO dao) {
33 this.dao = dao;
34 }
35 }
配置文件:
1 <!-- 依赖注入·setter注入 -->
2 <bean id="admin_xfwl" class="com.xfwl.spring.DI.Administrators">
3 <property name="aid" value="100001"></property>
4 <property name="aname" value="小风微凉"></property>
5 <property name="apwd" value="123456"></property>
6 </bean>
7 <bean id="dao" class="com.xfwl.spring.DI.DAO">
8 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
9 <property name="url" value="jdbc:oracle:thin:@***.36.17.**:1521:***"/>
10 <property name="username" value="***"/>
11 <property name="password" value="***"/>
12 </bean>
13 <bean id="daoImpl" class="com.xfwl.spring.DI.LoginDaoImp">
14 <property name="dao" ref="dao"/>
15 </bean>
3、接口注入
接口注入,关键是将第三方的外部资源注入到到我们想要的地方,关键是如何把数据信息注入到第三方资源对象中,然后再把第三方资源对象注入到指定的地方。
关键点在于配置文件:
1 <!-- 依赖注入·接口注入 -->
2 <!-- 配置数据源,使用C3P0连接池 的接口注入实现-->
3 <bean id="dataSource"
4 class="com.mchange.v2.c3p0.ComboPooledDataSource">
5 <property name="driverClass" value="${jdbc.driverClass}"></property>
6 <property name="jdbcUrl" value="${jdbc.url}"></property>
7 <property name="user" value="${jdbc.username}"></property>
8 <property name="password" value="${jdbc.password}"></property>
9 <!-- 指定连接池中保留的[最大连接数]. Default:15-->
10 <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
11 <!-- 指定连接池中保留的[最小连接数]-->
12 <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
13 <!-- 指定连接池的初[始化连接数] 取值应在minPoolSize 与 maxPoolSize 之间.Default:3-->
14 <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
15 <!-- [最大空闲时间],60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0-->
16 <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
17 <!-- 当连接池中的连接耗尽的时候c3p0[一次同时获取的连接数]. Default:3-->
18 <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
19 <!--
20 JDBC的标准,用以控制数据源内加载的PreparedStatements数量。
21 但由于预缓存的statements属于单个connection而不是整个连接池所以设置这个参数需要考虑到多方面的因数.
22 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0
23 -->
24 <property name="maxStatements" value="${jdbc.maxStatements}"/>
25 <!-- 每60秒检查所有连接池中的[空闲连接].Default:0 -->
26 <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
27 </bean>
稍微分析一下:
id:SpringIoc容器中配置的Bean对象。
class:第三方资源对象的接口全路径。
property :注入到第三方资源对象的数据。
创建一个测试类:TestBean.java
1 package com.xfwl.spring.DI;
2 import java.sql.SQLException;
3
4 import org.springframework.context.ApplicationContext;
5 import org.springframework.context.support.ClassPathXmlApplicationContext;
6 import org.springframework.context.support.FileSystemXmlApplicationContext;
7
8 /**
9 * Spring Ioc测试
10 * @function
11 * @author 小风微凉
12 * @time 2018-7-10 上午9:55:15
13 */
14 public class TestBean {
15 //绝对路径:FileSystemXmlApplicationContext
16 private static final String xmlAbsPath="E:/JAVA学习[【进阶学习】/JAVA回炉深造/进阶测试工作空间/多线程/SpringSources/src/com/xfwl/spring/DI/applicationContext.xml";
17 //项目相对路径:ClassPathXmlApplicationContext/ApplicationContext
18 private static final String xmlRelPath="com/xfwl/spring/DI/applicationContext.xml";
19 public static void main(String[] args) throws SQLException {
20 //拿到解析对象
21 ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext(xmlRelPath);
22 //【1】构造器注入-拿到Bean对象
23 //UserBean user=(UserBean) ctx.getBean("user_xfwl");
24 //System.out.println(user.toString());
25 //【2】setter注入-拿到Bean对象
26 //Administrators admin=(Administrators) ctx.getBean("admin_xfwl");
27 //System.out.println(admin.toString());
28 //【3】接口注入-拿到Bean对象
29 LoginDaoImp daoImpl=(LoginDaoImp) ctx.getBean("daoImpl");
30 daoImpl.queryCstListByNo("CB10000929");
31
32 }
33 }
测试结果:经过数据脱敏后的结果显示
1 log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
2 log4j:WARN Please initialize the log4j system properly.
3 log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
4 企业客户号:CB10000929,核心客户号:***********客户名称:赏渝沃舜汪物技术柔限星司,
5 企业客户号:CB10000764,核心客户号:***********客户名称:李靖,
6 企业客户号:CB10000720,核心客户号:***********客户名称:李靖333,
7 企业客户号:CB10000926,核心客户号:***********客户名称:赏渝沃舜汪物技术柔限星司,
8 企业客户号:CB10000927,核心客户号:***********客户名称:赏渝沃舜汪物技术柔限星司,
9 企业客户号:CB10000931,核心客户号:***********客户名称:赏渝沃舜汪物技术柔限星司,
10 企业客户号:CB10000940,核心客户号:***********客户名称:赏渝沃舜汪物技术柔限星司,
研究技术需要静下心来,一点一点地深究.......