Spring(一)

tech2026-08-13  0

Spring(一)

控制反转

Inversion of Control,缩写为IoC,把创建对象的权利交给框架,是框架的重要特征,它包括依赖注入和依赖查找.

工厂模式解耦代码

/** *BeanFactory:一个创建Bean对象的工厂: * * Bean:在计算机英语中,有可重用组件的含义 *JavaBean: 用java语言编写的可重用组件 * javabean != 实体类 * javabenan 的范围远大于实体类 * *创建service和dao对象: * 第一:需要一个配置文件来配置service 和 dao * 配置的内容:唯一标识 = 全限定类名 (key=value) 去获取这个全限定类名 * 第二:通过读取配置文件中配置的内容,反射创建对象 * 配置文件可以是 xml 也可以是 properties * * Properties(Java.util.Properties), * 该类主要用于读取Java的配置文件, * 不同的编程语言有自己所支持的配置文件, * 配置文件中很多变量是经常改变的,为了方便用户的配置, * 能让用户够脱离程序本身去修改相关的变量设置。 * */ //去读取 resources中的 bean.properties文件 /*public class BeanFactory { //定义一个Properties对象 private static Properties props; //使用静态代码块为Properties对象赋值 static { //实例化对象 props = new Properties(); //获取properties文件的流对象 用类加载器去读这个文件 InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); try { props.load(in); } catch (IOException e) { throw new ExceptionInInitializerError("初始化properties失败!"); } } *//** * 根据Bean的名称获取bean对象 * * @param beanName * @return *//* public static Object getBean(String beanName) { Object bean = null; String beanPath = props.getProperty(beanName); try { *//** * 用反射的方式来创建对象 * 并且因为newInstance() 每次都会调用默认构造函数, * 导致每次都初始化创建对象,每次创建不同对象它是多例的 * 因此需要解决(如下)!!!! *//* bean = Class.forName(beanPath).newInstance(); } catch (Exception e) { e.printStackTrace(); } return bean; } }*/ //去读取 resources中的 bean.properties文件 public class BeanFactory { //定义一个Properties对象 private static Properties props; //定义一个Map,用于存放我们需要创建的对象。我们把它称之为容器 private static Map<String,Object> beans; //使用静态代码块为Properties对象赋值 static { try { //实例化对象 props = new Properties(); //获取properties文件的流对象 用类加载器去读这个文件 InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); //实例化容器 beans=new HashMap<String, Object>(); //取出配置文件中所有的Key Enumeration keys = props.keys();//获得一个枚举类的keys //遍历枚举 while(keys.hasMoreElements()){ //取出每个key String key = keys.nextElement().toString(); //根据key获取value String beanPath = props.getProperty(key); //反射创建对象 Object value = Class.forName(beanPath).newInstance(); //把key和value放入容器中 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); } }

总结

/** -------------总结---------------------------- * AccountServiceImpl as = new AccountServiceImpl(); * AccountServiceImpl as = (AccountServiceImpl) BeanFactory.getBean("accountService"); * 这是两种截然不同的创建对象的方式 * 第一种 是 new app就是直接主动去找资源 * 第二种是app通过联系工厂 去找资源 ,工厂去控制资源,并且工厂为app提供资源 *而这就是IOC思想(控制反转) */

现在使用Spring 来进行解耦

1.1 什么是Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

1.2 Spring的优点
方便解耦,简化开发 (高内聚低耦合) Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理 spring工厂是用于生成beanAOP编程的支持 Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能声明式事务的支持 只需要通过配置就可以完成对事务的管理,而无需手动编程方便程序的测试 Spring对Junit4支持,可以通过注解方便的测试Spring程序方便集成各种优秀框架 Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持降低JavaEE API的使用难度 Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
1.3 Spring的体系结构

入门案例

配置文件

bean.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 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"> <!-- 把对象的创建交给spring来管理--> <bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl"></bean> <bean id="accountDao" class="x.xss.dao.impl.AccountDaoImpl"></bean> </beans>

表现层

/** * 模拟一个表现层,用于调用业务层 */ public class Client { /** * 获取spring的Ioc容器,并根据id获取对象 * * ApplicationContext的三个常用实现类: * * ClassPathXmlApplicationContext : 它可以加载类路径下的配置文件, * 要求配置文件必须在类路径下。 * 不在的话,加载不了。也就无法获 * 取核心容器对象 * * FileSystemXmlApplicationContext : 它可以加载磁盘任意路径下的配置文件 * (必须有访问权限) * AnnotationConfigApplicationContext : 它是用于读取注解创建容器的。 * * 核心容器的两个接口引发的问题 bean对象的创建默认是单例的 * 1, ApplicationContext: 单例对象适应 (实际开发中更多使用此接口) * 它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。 * 也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。 * *,2, BeanFactory; 多例对象适用 * 它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。 * 也就是说,什么时候根据id获取对象了,就什么时候才创建真正的对象。 * * * @param args */ public static void main(String[] args) { //1,获取核心容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\2019\\IdeaProjects\\day722_03spring\\src\\main\\resources\\bean.xml"); //2,根据id获取Bean对象 //两种方式 ,强转,或者是输入字节码文件强转 AccountService as = (AccountService) ac.getBean("accountService"); AccountDao adao = ac.getBean("accountDao", AccountDao.class); System.out.println(as); System.out.println(adao); // as.saveAccount(); /* //------- BeanFactory 创建对象,创建的bean是多例的---------- Resource resource = new ClassPathResource("bean.xml"); BeanFactory factory = new XmlBeanFactory(resource); AccountService as = (AccountService)factory.getBean("accountService"); System.out.println(as); */ } }

spring 中工厂的类结构图

BeanFactory 和 ApplicationContext 的区别

​ BeanFactory 才是 Spring 容器中的顶层接口。 ApplicationContext 是它的子接口。 BeanFactory 和 ApplicationContext 的区别: 创建对象的时间点不一样。 ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。 BeanFactory:什么使用什么时候创建对象。

ApplicationContext 接口的实现类

ClassPathXmlApplicationContext: 它是从类的根路径下加载配置文件 推荐使用这种 FileSystemXmlApplicationContext: 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。 AnnotationConfigApplicationContext: 当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

Spring对Bean 的管理细节

bean 标签

作用:

​ 用于配置对象让 spring 来创建的。

​ 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。

属性:

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:指定类中销毁方法名称。

1,创建bean的三种方式

方式一 :使用默认构造函数创建。

​ 在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性标签时。 ​ 采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建

/*配置文件中 */ <bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl"></bean> //实现类中 public class AccountServiceImpl implements AccountService { //默认构造函数 public AccountServiceImpl() { System.out.println("对象被创建了"); } }
方式二 别人写好的类,存在jar包中

​ 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

/** * 模拟一个工厂类(此类可能存在于jar包中, * 我们无法通过修改源码的方式来提供默认构造函数 */ public class InstanceFactory { public AccountService getAccountServive(){ return new AccountServiceImpl(); } } <!-- 此种方式是: 先把工厂的创建交给 spring 来管理。 然后在使用工厂的 bean 来调用里面的方法 factory-bean 属性:用于指定实例工厂 bean 的 id。 factory-method 属性:用于指定实例工厂中创建对象的方法。 --> <bean id="instanceFactory" class="x.xss.factory.InstanceFactory"></bean> <!--accountService的创建不再自己创建了,而是去使用 nstanceFactory,所以加上下面的配置--> <bean id="accountService" factory-bean="instanceFactory" <--找到此类中的--> factory-method="getAccountServive"> <--此方法--> </bean>
方式三 别人写好的类,存在jar包中

​ 使用工厂中的静态方式创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

/** * 模拟一个工厂类(此类可能存在于jar包中, * 我们无法通过修改源码的方式来提供默认构造函数 * 这里是静态的方法 */ public class StaticFactory { public static AccountService getAccountServive(){ return new AccountServiceImpl(); } } <!--使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器 id 属性:指定 bean 的 id,用于从容器中获取 class 属性:指定静态工厂的全限定类名 factory-method 属性:指定生产对象的静态方法--> <bean id="accountService" class="x.xss.factory.StaticFactory" factory-method="getAccountServive"> </bean>

2,bean对象的作用范围

默认是单例的 bean标签的scope属性; 作用: 用于指定bean的作用范围 取值: singleton : 单例的(也是默认值)(常用) prototype : 多例的 (常用) request : 作用于web应用的 请求 范围 session : 作用于web应用的 会话 范围 global-session: 作用于 集群环境的会话范围(全局会话范围) ,当不是集群环境时,就是session

<bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl" scope="singleton" init-method="init" destroy-method="destory"></bean>

3,bean对象的生命周期

单例对象 出生 容器创建时,对象出生 活着 死亡 容器销毁时,对象消亡 总结:单例对象的生命周期与容器相同 多例对象 出生 当使用对象时,spring框架会创建 活着 对象在使用过程中 bean就一直存在 死亡 当对象长时间不用,且没有别的对象引用时, ·有java的垃圾回收器回收

spring 的依赖注入

依赖注入: Dependency Injection IOC的作用: 降低程序间的耦合(依赖关系) 依赖关系的管理: 以后都交给了spring维护 在当前类中需要用到其他类的对象,由spring来提供,我们只需在配置文件中说明 依赖关系的维护: 称之为:依赖注入 依赖注入: 能注入的数据有三类 基本类型和String 其它bean类型(在配置文件中或者注解配置过的bean) 复杂类型/集合类型 注入的方式:有三种 第一种:使用构造函数提供 第二种: 使用set方法提供 第三种: 使用注解提供

1,构造函数的注入

​ 使用标签: constructor-arg ​ 标签出现的位置: bean 标签的内部 ​ 标签中的属性 : ​ type :用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型(不能独立实现注入的功能)

​ index: 用于指定要注入的数据给构造函数中指定索引位置的参数赋值。参数索引的位置从0开始。

​ name: 用于指定给构造函数中指定名称的参数赋值 (常用的)

=以上三个用于指定给构造函数中的哪个参数赋值===

​ value: 用于提供基本类型和String类型的数据 ​ ref : 用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象。 ​ 例如出现过的bean对象: ​ ​ 优势: ​ 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。 ​ 劣势: ​ 改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据, ​ 也还是要提供。

<bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl"> <constructor-arg name="aaa" value="小明"></constructor-arg> <constructor-arg name="bbb" value="18"></constructor-arg> <constructor-arg name="ccc" ref="now"></constructor-arg> </bean> <!--配置一个日期对象--> <bean id="now" class="java.util.Date"></bean> /** * 账户的业务层实现类 */ public class AccountServiceImpl implements AccountService { //如果是经常变化的数据,并不适用于注入的方式 private String aaa; private Integer bbb; private Date ccc; //构造方法 public AccountServiceImpl(String aaa, Integer bbb, Date ccc) { this.aaa = aaa; this.bbb = bbb; this.ccc = ccc; } public void saveAccount() { System.out.println("service中的saveAccount方法被执行了..."+ aaa + "," + bbb + "," + ccc); } }

2, set方法注入

​ 涉及的标签:property ​ 出现的位置:bean标签的内部 ​ 标签的属性 ​ name:用于指定注入时所调用的set方法名称 ​ value:用于提供基本类型和String类型的数据 ​ ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象 ​ 优势: ​ 创建对象时没有明确的限制,可以直接使用默认构造函数 ​ 弊端: ​ 如果有某个成员必须有值,则获取对象时有可能set方法没有执行。

<bean id= "accountService2" class= "x.xss.service.impl.AccountServiceImpl2"> <property name="aaa" value="小红"></property> <property name="bbb" value="15"></property> <property name="ccc" ref="now"></property> </bean> /** * 账户的业务层实现类 */ public class AccountServiceImpl2 implements AccountService { //如果是经常变化的数据,并不适用于注入的方式 private String aaa; private Integer bbb; private Date ccc; //set方法 public void setAaa(String aaa) { this.aaa = aaa; } public void setBbb(Integer bbb) { this.bbb = bbb; } public void setCcc(Date ccc) { this.ccc = ccc; } public void saveAccount() { System.out.println("service中的saveAccount方法被执行了..."+ aaa + "," + bbb + "," + ccc); } }

3,复杂类型的注入/集合类型的注入(实际开发中常用!!!)

​ 用于给List结构集合注入的标签: ​ list array set ​ 用于个Map结构集合注入的标签: ​ map props ​ 结构相同,标签可以互换

<bean id="accountService3" class="x.xss.service.impl.AccountServiceImpl3"> <property name="a"> <set> <value>数组1</value> <value>数组2</value> <value>数组3</value> </set> </property> <property name="b"> <array> <value>List1</value> <value>List2</value> <value>List3</value> </array> </property> <property name="c"> <set> <value>Set1</value> <value>Set2</value> <value>Set3</value> </set> </property> <property name="d"> <props> <prop key="map1">m111</prop> <prop key="map2">m222</prop> </props> </property> <property name="e"> <map> <entry key="写法1" value="Properties1111"></entry> <entry key="写法2"> <value>Properties2222</value> </entry> </map> </property> </bean> /** * 账户的业务层实现类 */ public class AccountServiceImpl3 implements AccountService { private String[] a; private List<String> b; private Set<String> c; private Map<String,String>d; private Properties e; //set 方法 public void setA(String[] a) { this.a = a; } public void setB(List<String> b) { this.b = b; } public void setC(Set<String> c) { this.c = c; } public void setD(Map<String, String> d) { this.d = d; } public void setE(Properties e) { this.e = e; } public void saveAccount() { System.out.println(Arrays.toString(a)); System.out.println(b); System.out.println(c); System.out.println(d); System.out.println(e); } } g,String>d; private Properties e; //set 方法 public void setA(String[] a) { this.a = a; } public void setB(List<String> b) { this.b = b; } public void setC(Set<String> c) { this.c = c; } public void setD(Map<String, String> d) { this.d = d; } public void setE(Properties e) { this.e = e; } public void saveAccount() { System.out.println(Arrays.toString(a)); System.out.println(b); System.out.println(c); System.out.println(d); System.out.println(e); } }
最新回复(0)