以我们进行jdbc操作时的注册驱动过程为例:
Class.forName(“com.mysql.cj.jdbc.Driver”);
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
从上面代码中我们可以看出,第一种加载驱动时com.mysql.cj.jdbc.Driver是以字符串的形式存在的,而第二种则是导入了com.mysql.cj.jdbc.Driver这一个驱动类。从结果上来说,上面两个语句都实现了组测驱动,但是在依赖程度上来讲,两个方法是不同的,接下来我们运行测试代码(不要在pom.xml中添加mysql-connector-java的依赖):
public class JdbcDemo1 {
public static void main(String[]args) throws Exception {
//1.注册驱动
Class.forName(“com.mysql.cj.jdbc.Driver”);
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
//2.获取连接
Connection conn=DriverManager.getConnection(“jdbc:mysql://localhost:3306/spring?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false”
,“root”,“520992”);
//3.获取操作数据库的预处理对象
PreparedStatement pstm =conn.prepareStatement(“select * from account”);
//4.执行SQL,得到结果
ResultSet rs=pstm.executeQuery();
//5.遍历结果集
while(rs.next()){
System.out.println(rs.getString(“name”));
}
//6.释放资源
rs.close();
pstm.close();
conn.close();
}
}
使用Class.forName("com.mysql.cj.jdbc.Driver");
的运行结果:
使用DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
的运行结果:
第一种方法在运行时报了:java.lang.ClassNotFoundException异常,而第二种方法直接在编译期报了程序包不存在的错误。显然第一种方法比第二种方法更具有优势,降低了对程序包的依赖程度。
从上面可以看出,降低程序间的耦合(解耦)的思路是:
第一步,使用反射来创建对象,而避免使用new关键字
第二步:通过读取配置文件来获取要创建的对象全限定类名
[](()Spring中的IOC
IOC(Inversion of Control,控制反转)。这是spring的核心。IOC 并不是一种技术,只是一种思想,一种降低程序间耦合,优化程序的设计思想。在学习Spring之前,我们在编写程序时,我们的类中往往会new出许多依赖对象,从而使程序间的耦合度越来越高。
所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI)),装配对象,配置对象,并且管理这些对象的整个生命周期。IOC(控制反转)或DI(依赖注入)把应用的代码量降到最低,使应用容易测试,单元测试不再需要单例和JNDI查找机制,最小的代价和最小的侵入性实现了较低的耦合度。IOC容器支持加载服务时的饿汉式初始化和懒加载。
案例:基于xml的IOC搭建入门
项目目录:
在pom.xml添加spring框架的相关依赖:org.springframework-spring-context-5.0.2.RELEASE
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”> 4.0.0 org.example spring_day01_spring1 1.0-SNAPSHOT jar org.springframework spring-context 5.0.2.RELEASE 创建业务层接口和实现类: /** @Author: Ly @Date: 2020-07-21 16:29 账户业务层的接口 */ public interface IAccountService { /** */ void saveAccount(); } /** @Author: Ly @Date: 2020-07-21 16:31 账户的业务成实现类 */ public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao=new AccountDaoImpl(); public AccountServiceImpl(){ System.out.println(“对象创建了”); } public void saveAccount() { accountDao.saveAccount(); } } 创建持久层接口和实现类: /** @Author: Ly @Date: 2020-07-21 16:33 账户的持久层接口 */ public interface IAccountDao { /** */ void saveAccount(); } /** */ public class AccountDaoImpl implements IAccountDao { public void saveAccount() { System.out.println(“保存了账户”); } } 配置Bean.xml文件 xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation="http://www.springframework.org/schema/be 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 ans http://www.springframework.org/schema/beans/spring-beans.xsd"> 测试代码: public class Client { /* 获取spring的Ioc核心容器,并根据id获取对象 ApplicationContext的三个常用实现类 核心容器的两个接口引发出的问题: ApplicationContext: 单例对象适用 一般采用此接口 它在创建核心容器时,创建对象采用的策略是采用立即加载方式,只要一读取完配置文件马上就创建文件中的配置对象。 BeanFactory: 多例对象适用 它在创建核心容器时,创建的对象采取的策略是采用延迟加载的方式,什么时候id获取对象了,什么时候才真正的创建对象。 */ public static void main(String[]args){ //1.获取核心容器对象 ApplicationContext ac=new ClassPathXmlApplicationContext(“bean.xml”); //ApplicationContext ac=new FileSystemXmlApplicationContext(“F:\Intellij idea\spring\spring_day01_spring1\src\main\resources\bean.xml”);//配置文件对应的磁盘中的绝对路 //2.根据id获取Bean对象 IAccountService as=(IAccountService)ac.getBean(“accountService”); IAccountDao ad=ac.getBean(“accountDao”,IAccountDao.class); /*//------BeanFactory获取核心容器对象--------- Resource resource=new ClassPathResource(“bean.xml”); BeanFactory factory=new XmlBeanFactory(resource); IAccountService as=(IAccountService)factory.getBean(“accountService”); IAccountDao ad=factory.getBean(“accountDao”,IAccountDao.class);*/ System.out.println(as); System.out.println(ad); } } 运行结果: 从结果中可以看出,我们并没有使用new的方式实例化对象,但是我们的对象已经被实例化了。 [](()实例化 Bean对象 标签的属性: id: 给对象在容器中提供一个唯一标识。用于获取对象。 class: 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。 scope: 指定对象的作用范围。 singleton :默认值,单例的. prototype :多例的. request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中. session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中. global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session init-method: 指定类中的初始化方法名称。 destroy-method: 指定类中销毁方法名称。 创建Bean的三种方式 项目结构: 第一种方式: 第二种方式: /** @Author: Ly @Date: 2020-07-23 23:27 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数) */ public class InstanceFactory { public IAccountService getAccountService(){ return new AccountServiceImpl(); } } 第三种方法: /** @Author: Ly @Date: 2020-07-23 23:27 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数) */ public class StaticFactory { public static IAccountService getAccountService(){ return new AccountServiceImpl(); } } bean 的作用范围和生命周期: xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> scope=“prototype” init-method=“init” destroy-method=“destroy”> [](()依赖注入 依赖注入:Dependency Injection, 它是 spring 框架核心 IOC的具体实现。 我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。我么知道IOC的作用是降低程序间的耦合,而不是消除耦合。对于我们项目中业务层和持久层的依赖关系,我们可以交给 spring 来维护,在我们的类中需要用到其他类的对象时,可以由由spring为我们提供。通过spring框架把持久层对象传入到业务层,从而省去我们自己获取的步骤。 依赖注入可以注入三种类型的数据: 同时有三种注入方式: 案例: 构造函数注入: 通过使用类中的构造函数,给成员变量赋值。在这之中,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。具体代码如下: /** @Author: Ly @Date: 2020-07-21 16:31 账户的业务成实现类 */ public class AccountServiceImpl implements IAccountService { //如果是经常变化的数据,并不适用于注入的方式 private String name; private Integer age; private Date birthday; public AccountServiceImpl(String name,Integer age,Date birthday){ this.name=name; this.age=age; this.birthday=birthday; } public void saveAccount() { System.out.println(“service中的saveAccount方法执行了,”+name+“,”+age+“,”+birthday); } } set方法注入 在类中提供需要注入成员的 set 方法,进行注入。具体代码如下: /** @Author: Ly @Date: 2020-07-21 16:31 账户的业务成实现类 */ public class AccountServiceImpl2 implements IAccountService { //如果是经常变化的数据,并不适用于注入的方式 private String name; private Integer age; private Date birthday; public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } public void saveAccount() { System.out.println(“service中的saveAccount方法执行了,”+name+“,”+age+“,”+birthday); } } 复杂类型注入: 依赖注入可以注入复杂的数据类型,如s数组、集合,同时注入这些复杂数据也是set方法注入的方式,只不过变量的数据类型都是集合。具体代码如下: /** @Author: Ly @Date: 2020-07-21 16:31 账户的业务成实现类
ClassPathXmlApplicationContext: 它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了
FileSystemXmlApplicationContext: 他可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:它是用于读取注解创建容器的
Bean是Spring容器初始化、装配和管理的对象,它是由 spring 来创建的,默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其它属性和标签时,采用的就是默认函数创建bean对象,此时如果类中没有默认构造函数则对象无法创建。
使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
使用工厂中的静态方法创建对象(使用某个静态方法创建对象,并存入spring容器)
基本类型和string、其他bean类型(在配置文件中或者注解配置过的bean)、复杂类型/集合类型
构造函数提供、set方式提供、注解提供