package com.ithema.jdbc; import java.sql.*; /** * 程序耦合 */ public class JdbcDemo1 { public static void main(String[] args) { try { DriverManager.registerDriver(new com.mysql.jdbc.Driver()); Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/fresh","root","root"); PreparedStatement pstm=conn.prepareStatement("select * from usertable"); ResultSet rs=pstm.executeQuery(); while (rs.next()){ System.out.println(rs.getString("username")); } rs.close(); pstm.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
下面是pom里面的依赖包文件的引入java
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies>
当程序正常运行,能够看到是有查询到数据输出mysql
可是当咱们把jdbc的依赖包注销掉sql
<!--<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies>-->
程序还会正常查询语句嘛,显示结果以下数据库
在程序编译的初期就显示,这个依赖类不存在,那程序就不能运行,这个就是咱们说的耦合!!简单点来讲就是程序之间的依赖关系架构
耦合主要分为两种:类之间的依赖、方法之间的依赖ide
解耦的含义就是下降程序之间的依赖关系,因此咱们在实际开发中要作到编译期不依赖,运行期才依赖函数
如何解决这个依赖问题?类之间的依赖关系测试
一、在建立对象的时候,使用反射来建立对象,避免使用new关键ui
划线部分就是使用了反射注册驱动,里面的内容只是字符串,不是一个类,可是里面字符串是一个mysql数据库,当之后要换数据库的时候仍是要改驱动spa
二、经过读取配置文件来获取建立对象全限定类名
三层架构咱们前面都学过,层与层之间都是相互依赖的关系,ui(视图层)调用service里面的实现方法,service调用dao层持久层里面的方法实现数据的查询,这就使得相互之间的依赖关系很强,缺乏那一个实现方法,程序都不能正常实现,那有什么好的解决方法没???
解决方法1、建立一个BeanFactory,用工厂模式解耦
实现思路
一、须要一个文件来配置咱们的service和dao,配置的内容为:惟一标识=全限定类名(keyvalue)
二、经过读取配置文件中配置的内容来反射建立对象
package com.ithema.jdbc.factory; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; /** * 一个Bean对象的工厂 * Bean在计算机英语中,有可重用组件的含义 * JavaBean:用Java语言编写的可重用组件 * JavaBean>实体类 * 做用它就是建立咱们使用service和dao对象的 * * 实现方法: * 一、须要一个文件来配置咱们的service和dao * 配置内容:惟一标识=全限定类名(keyvalue) * 二、经过读取配置文件中配置的内容,反射对象 * * 配置文件能够是properties或者是xml */ public class Beanfactory { //定义一个properties对象 private static Properties props; //使用静态代码块建立Properites对象 static { try { //实例化对象 props=new Properties(); //获取properites流对象 InputStream in=Beanfactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); }catch (Exception e){ throw new ExceptionInInitializerError("初始化properties失败"); } } /** * 根据bean的名称获取bean对象 * @param beanName * @return */ public static Object getBean(String beanName) { Object bean=null; try { String beanPath = props.getProperty(beanName); bean = Class.forName(beanPath).newInstance();//经过反射来建立对象 } catch (Exception e) { e.printStackTrace(); } return bean; } }
properites配置文件内容
#全限定类名 accountService=com.ithema.jdbc.service.impl.AccountServiceImpl accountDao=com.ithema.jdbc.dao.impl.AccountDaoImpl
package com.ithema.jdbc.service; /** * 帐户业务层的接口 */ public interface IAccountService { /** * 模拟保存帐户 */ void saveAccount(); }
package com.ithema.jdbc.service.impl; import com.ithema.jdbc.dao.IAccountDao; import com.ithema.jdbc.dao.impl.AccountDaoImpl; import com.ithema.jdbc.factory.Beanfactory; import com.ithema.jdbc.service.IAccountService; /** * 帐户的业务层实现类 */ public class AccountServiceImpl implements IAccountService { //private IAccountDao accountDao=new AccountDaoImpl(); private IAccountDao accountDao= (IAccountDao) Beanfactory.getBean("accountDao"); public void saveAccount(){ accountDao.saveAccount(); }; }
package com.ithema.jdbc.dao; /** * 帐户的持久层接口 */ public interface IAccountDao { void saveAccount(); }
package com.ithema.jdbc.dao.impl; import com.ithema.jdbc.dao.IAccountDao; /** * 帐户持久层实现类 */ public class AccountDaoImpl implements IAccountDao { @Override public void saveAccount() { System.out.println("保存了帐户!!"); } }
测试类实现代码,测试结果以下
package com.ithema.jdbc.ui; import com.ithema.jdbc.factory.Beanfactory; import com.ithema.jdbc.service.IAccountService; import com.ithema.jdbc.service.impl.AccountServiceImpl; /** * 模拟一个表现层,用于调用业务层 */ public class Client { public static void main(String[] args) { //IAccountService as=new AccountServiceImpl(); IAccountService as=(IAccountService) Beanfactory.getBean("accountService"); as.saveAccount(); } }
可是用工厂模式解耦依然存在问题,当在test屡次建立对象时候结果以下
package com.ithema.jdbc.ui; import com.ithema.jdbc.factory.Beanfactory; import com.ithema.jdbc.service.IAccountService; import com.ithema.jdbc.service.impl.AccountServiceImpl; /** * 模拟一个表现层,用于调用业务层 */ public class Client { public static void main(String[] args) { //IAccountService as=new AccountServiceImpl(); for (int i=0;i<5;i++){ IAccountService as=(IAccountService) Beanfactory.getBean("accountService"); System.out.println(as); } //as.saveAccount(); } }
每次调用构造函数都会建立一个对象,打印出来的是多例对象,那么单例对象和多例对象有什么区别???
多例每次初始化都会建立一个对象,这样的话就会出现线程问题,每次获取到的对象都是不同的,而咱们在servlet和dao层中通常都是采用单例模式
形成建立多例对象的缘由
那么有什么办法能解决这个问题嘛??那就是建立一个Map集合来保存反射建立出来的对象
package com.ithema.jdbc.factory; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * 一个Bean对象的工厂 * Bean在计算机英语中,有可重用组件的含义 * JavaBean:用Java语言编写的可重用组件 * JavaBean>实体类 * 做用它就是建立咱们使用service和dao对象的 * * 实现方法: * 一、须要一个文件来配置咱们的service和dao * 配置内容:惟一标识=全限定类名(keyvalue) * 二、经过读取配置文件中配置的内容,反射对象 * * 配置文件能够是properties或者是xml */ public class Beanfactory { //定义一个properties对象 private static Properties props; //定义一个Map,用于存放咱们建立的对象,咱们把它称之为容器 private static Map<String,Object> beans; //使用静态代码块建立Properites对象 static { try { //实例化对象 props=new Properties(); //获取properites流对象 InputStream in=Beanfactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); //实例化容器 beans=new HashMap<String,Object>(); //取出配置文件中全部的key Enumeration keys=props.keys(); while (keys.hasMoreElements()){ String key=keys.nextElement().toString(); //获取value值 String beanPath=props.getProperty(key); //建立反射对象 Object value=Class.forName(beanPath).newInstance(); //保存到容器中 beans.put(key,value); } }catch (Exception e){ throw new ExceptionInInitializerError("初始化properties失败"); } } /** * 根据bean的名称获取bean对象 * @param beanName * @return */ public static Object getBean(String beanName) { return beans.get(beanName); } /* public static Object getBean(String beanName) { Object bean=null; try { String beanPath = props.getProperty(beanName); bean = Class.forName(beanPath).newInstance();//经过反射来建立对象,可是每次都会默认调用构造函数建立新的对象 //须要一个容器来保存对象 } catch (Exception e) { e.printStackTrace(); } return bean; }*/ }
再次运行test类Client,获得就是一个单例对象