下拉找到Access to Binaries, 进入Spring Framework Artifacts
进入到Spring的仓库(这里有Spring的各个版本的jar包)
具体路径 snapshot->org->springframework->spring
下载网址 https://repo.spring.io/artifactory/snapshot/org/springframework/spring/
这里博主已把所有资源上传, 无需再去官网下载, 资料如下
各个jar包的含义
在线文档 | https://docs.spring.io/spring-framework/reference/ |
---|---|
离线文档 | spring-framework-5.3.8\docs\reference\html\index.html |
离线API | spring-framework-5.3.8\docs\javadoc-api\index.html |
Spring核心学习内容 IOC, AOP, jdbcTemplate, 声明式事务
Spring可以整合其它的框架(解读: Spring是管理框架的框架)
Spring有两个核心的概念: IOC 和 AOP
IOC [Inversion Of Control 反转控制]
传统的开发模式[JDbcUtils / 反射], 程序------>环境 //程序读取环境配置, 然后自己创建对象
以连接到数据库为例
程序员编写程序, 在程序中读取配置信息
创建对象, 使用对象完成任务
Spring方式
Spring根据配置文件xml / 注解, 创建对象, 并放入到容器(ConcurrentHashMap). 并且可以完成对象之间的依赖
当需要使用某个对象实例的时候, 就直接从容器中获取即可
这样程序员可以更加关注如何使用对象完成相应的业务(以前是new -> 现在是注解 / 配置)
DI - Dependency Injection依赖注入, 可以理解成是IOC的别称
Spring最大的价值是 通过配置, 给程序员提供需要使用的对象web层[Servlet (Action/Controller)/ Service / Dao / JavaBean(entity)]对象
这是核心价值所在, 也是ioc的具体体现, 实现解耦
需求: 通过Spring的方式[配置文件], 获取JavaBean-Monster的对象, 并给该对象的属性赋值, 输出该对象的信息
package com.zzw.spring.bean; public class Monster { private String monsterId; private String name; private String skill; //无参构造器: Spring底层反射创建对象时, 需要使用 public Monster() { } //有参构造器, setter, getter, toString() }
创建好之后, 右上角进行配置, 不难
说明: xmlns表示xml namespace, 即xml命名空间
测试
package com.zzw.spring.test; public class SpringBeanTest { @Test public void getMonster() { //解读 //1.创建容器 ApplicationContext //2.该容器和容器配置文件关联 //3.习惯用接口的形式接收 ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); //3.通过getBean获取对应的对象 // 默认返回的是Object, 但是运行类型是Monster //Object monster01 = ioc.getBean("monster01"); Monster monster01 = (Monster) ioc.getBean("monster01"); //4.输出 System.out.println("monster01" + monster01 + ", monster01运行类型" + monster01.getClass()); System.out.println("monster01" + monster01 + ", 属性name=" + monster01.getName() + ", monsterId="+ monster01.getMonsterId()); //5.也可以在获取的时候, 直接指定Class类型, 可以再次获取 Monster monster011 = ioc.getBean("monster01", Monster.class); System.out.println("monster011=" + monster011); System.out.println("monster011.name=" + monster011.getName()); System.out.println("ok~~~"); } }
解释类加载路径
ApplicationContext ioc = new ClassPathXmlApplicationContext(“beans.xml”);
//验证类加载路径 @Test public void classPath() { File file = new File(this.getClass().getResource("/").getPath()); //看到类的加载路径 System.out.println("file=" + file); }
小技巧分享
判断是否是懒加载: 是事先创建好, 还是等到用户使用的时候再创建.
lazyInit: false. 说明beans.xml中对象的创建不是懒加载.
用Debug的方式, 看一下Spring容器的处理机制
ioc->beanFactory->beanDefinitionMap
beanDefinitionMap / table
index=217
table / propertyValues
beanFactory->singletonObjects
singletonObjects / table
beanFactory / beanDefinitionNames
题目: 查看容器注入了哪些bean对象, 输出bean的id
String[] beanDefinitionNames = ioc.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println("beanDefinitionName=" + beanDefinitionName); }
需求说明
- 自己写一个简单的Spring容器, 通过读取beans.xml, 获取第1个JavaBean: Monster的对象, 并给该对象的属性赋值, 放入到容器中, 并输出该对象信息
- 也就是说, 不使用Spring原生框架, 我们自己简单模拟实现
- 了解Spring容器的简单机制
思路分析
实现
引入dom4j-1.6.1.jar包
ZzwApplicationContext.java
package com.zzw.spring.zzwapplicationcontext; /** * @author 赵志伟 * @version 1.0 * 1.这个程序用于实现Spring的一个简单容器机制 * 2.后面还会详细实现 * 3.这里我们实现如何将beans.xml文件进行解析, 并生成对象, 放入容器中 * 4.提供一个方法 getBean(id) 返回对应的对象 * 5.这里就是一个开胃小点心, 理解Spring容器的机制 */ @SuppressWarnings({"all"}) public class ZzwApplicationContext { private ConcurrentHashMapsingletonObjects = new ConcurrentHashMap<>(); //构造器 //接收一个容器的配置文件 比如 beans.xml, 该文件默认在src目录下 public ZzwApplicationContext(String iocBeanXmlFile) throws Exception { //1.得到类加载路径: // /D:/idea_project/zzw_spring/spring/out/production/spring/ String path = this.getClass().getResource("/").getPath(); //2.创建解析器 SAXReader reader = new SAXReader(); //3.得到document对象 Document document = reader.read(new File(path + iocBeanXmlFile)); //4.获取rootElement Element rootElement = document.getRootElement(); //5.得到第1个bean-monster01 Element bean = (Element) rootElement.elements("bean").get(0); //6.获取第一个bean-monster01的相关属性 => beanDefinitionMap String id = bean.attributeValue("id"); String ClassFullPath = bean.attributeValue("class"); List properties = bean.elements("property"); //这里不再遍历, 直接获取 Integer monsterId = Integer.parseInt(properties.get(0).attributeValue("value")); String name = properties.get(1).attributeValue("value"); String skill = properties.get(2).attributeValue("value"); //7.使用反射创建对象 => 回顾反射机制 Class> aClass = Class.forName(ClassFullPath); //这里instance就是Monster对象 Monster o = (Monster) aClass.newInstance(); //给o对象通过反射来赋值 => 这里先简化 o.setMonsterId(monsterId); o.setName(name); o.setSkill(skill); //8.将创建好的对象放入到singletonObjects singletonObjects.put(id, o); } public Object getBean(String id) { //这里可以再处理一下 return singletonObjects.get(id); } }
测试 ZzwApplicationContextTest
package com.zzw.spring.zzwapplicationcontext; public class ZzwApplicationContextTest { public static void main(String[] args) throws Exception { ZzwApplicationContext ioc = new ZzwApplicationContext("beans.xml"); Monster monster01 = (Monster) ioc.getBean("monster01"); System.out.println("monster01=" + monster01); System.out.println("monster01.name=" + monster01.getName()); System.out.println("ok~"); } }
在beans.xml中, 注入两个Monster对象, 但是不指定id, 运行会不会报错?
如果不会报错, 如果知道id, 并获取Monster对象.
public class homework01 { @Test public void getMonster() { //1.创建容器, 习惯用接口的形式接收 ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Monster monster1 = ioc.getBean("com.zzw.spring.bean.Monster#0", Monster.class); System.out.println("monster1=" + monster1); Monster monster2 = ioc.getBean("com.zzw.spring.bean.Monster#1", Monster.class); System.out.println("monster2=" + monster2); System.out.println("ok~"); } }
创建一个Car类, 要求
- 创建ioc容器文件(配置文件), 并配置一个Car对象(bean).
- 通过java程序到ioc容器获取该bean对象, 并输出
public class Car { private Integer id; private String name; private Double price; public Car() { System.out.println("car对象 无参构造器被执行"); } //有参构造器, setter, getter, toString()
beans1.xml
public class homework02 { public static void main(String[] args) { //1.创建容器对象 ApplicationContext ioc = new ClassPathXmlApplicationContext("beans1.xml"); Car car01 = ioc.getBean("car01", Car.class); System.out.println("car01=" + car01); System.out.println("car01.name=" + car01.getName()); System.out.println("ok~"); } }
案例: 通过spring的ioc容器, 获取一个bean对象, 获取方式: 按类型.
演示通过bean的类型获取对象
@Test public void getBeanByType() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); //直接传入class对象/类型 Monster bean = ioc.getBean(Monster.class); System.out.println("bean=" + bean); }
细节
按照类型获取bean, 要求ioc容器中的同一个类的bean只能有一个, 否则会抛出异常 NoUniqueBeanDefinationException
这种方式的应用场景: 比如XxxAction / Servlet / Controller, 或XxxService在一个线程中只需要一个对象实例(单例)的情况
在容器配置文件(比如beans.xml)中给属性赋值. 底层是通过setter方法完成的. 所以需要提供setter方法.
演示通过构造器来设置属性
@Test public void setBeanByConstructor() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Monster monster03 = ioc.getBean("monster03", Monster.class); System.out.println("monster03=" + monster03); }
通过index属性来区分是第几个参数;
通过type属性来区分是什么类型(按照顺序, 这是可以的)
xmlns:p=“http://www.springframework.org/schema/p”
演示通过p名称空间来设置属性
public class SpringBeanTest { @Test public void setBeanByP() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Monster monster06 = ioc.getBean("monster06", Monster.class); System.out.println("monster06=" + monster06); } }
引用注入其它bean对象
在spring的ioc容器, 可以通过ref来实现bean对象的相互引用[ref全称: reference]
package com.zzw.spring.service; public class MemberServiceImpl { private MemberDaoImpl memberDao; public MemberDaoImpl getMemberDao() { return memberDao; } public void setMemberDao(MemberDaoImpl memberDao) { this.memberDao = memberDao; } public void add() { System.out.println("MemberServiceImpl add方法被调用..."); memberDao.add(); } }
package com.zzw.spring.dao; public class MemberDaoImpl { public MemberDaoImpl() { System.out.println("MemberDaoImpl 构造器..."); } public void add() { System.out.println("MemberDaoImpl add方法被执行"); } }
通过ref来设置bean属性
public class SpringBeanTest { @Test public void setBeanByRef() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class); memberService.add(); } }
引用/注入内部bean对象
在spring的ioc容器, 可以直接配置内部bean对象
通过内部bean, 设置属性
public class SpringBeanTest { @Test public void setBeanByPro() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); MemberServiceImpl memberService2 = ioc.getBean("memberService2", MemberServiceImpl.class); memberService2.add(); } }
下乘: Spring系列二:基于XML配置bean