spring共四天
第一天:spring框架的概述以及spring中基于XML的IOC配置
第二天:spring中基于注解的IOC和IOC的案例
第三天:spring中的aop和基于XML以及注解的AOP配置
第四天:spring中的JdbcTemlate以及Spring事务控制
1、spring的概述
1)spring是什么
2)spring的两大核心
3)spring的发展历程和优势
4)spring体系结构
2. 程序的耦合及解耦
1)曾经案例中问题
2)工厂模式解耦
3. IOC概念和spring中的IOC
1) spring中基于XML的IOC环境搭建
4. 依赖注入(Dependency Injection)
1、spring的概述以及体系结构
参考文档以及视频的介绍。
注意,我们使用Maven来构建我们的工程,因此我们不需要Spring的开发jar包,只需要在Maven中导入Spring的坐标即可。
下面是Spring的开发包目录
2、IOC 的概念和作用
2.1 程序的耦合和解耦
什么是程序耦合?(见文档—2.1.1 什么是程序的耦合 )
编写jdbc的代码用于程序间的耦合(见视频7,项目spring_day01_jdbc 的分析)。
耦合的分析如下代码:
package com.lkj.jdbc;
/**
* 程序的耦合
* 耦合:程序间的依赖关系,包括:
* 1)类之间的依赖
* 2)方法间的依赖
*
* 解耦: 降低程序间的依赖关系
* 实际开发中: 应该做到,编译期不依赖,运行时才依赖。
*
* 解耦的思路:
* 第一步:使用反射来创建对象,而避免使用new关键字。
* 如下分析,new创建对象就会依赖于某一个类或者jar包,会在编译期间就产生依赖,因为编译期间就会检查使用的类;
* 而通过反射的方式,则只是依赖某个字符串,编译的时候不检测,运行的时候才会产生依赖
*
* 第二步:通过读取配置文件来获取要创建的对象全限定类名
* 如下,我们的 Class.forName("com.mysql.jdbc.Driver"); 如果想使用其他数据库,仍然需要修改字符串的内容。
* 而这一需要修改代码。如果我们通过配置文件的方式读取类型,就只需要修改配置文件即可!
*
*/
public class JdbcTest1
{
public static void main(String[] args) throws Exception
{
/**
* 如果我们将mysql的依赖删除,那么如果使用 DriverManager.registerDriver(new com.mysql.jdbc.Driver());在编译期间就会出异常。
* 如果使用:Class.forName("com.mysql.jdbc.Driver"); 此时不需要依赖于具体的类或者jar包,即使没有mysql的驱动,
* 也只是报运行时异常:ClassNotFoundException , 而不会在编译期间出错,这样可以解耦。
*/
//1.注册驱动
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());//这种方法在编译期就依赖于某个类或者某个jar包
//在这里,“com.mysql.jdbc.Driver”只是一个字符串,我们不需要像上面一样依赖于具体的某个驱动类,这个类就可以相对独立出来
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lkj_spring", "root", "root");
//3.获取操作数据库的预处理对象
PreparedStatement ps = conn.prepareStatement("select * from account");
//4.执行SQL,得到结果集
ResultSet resultSet = ps.executeQuery();
//5.遍历结果集
while(resultSet.next())
{
System.out.println(resultSet.getString("name"));
}
//6.释放资源
resultSet.close();
ps.close();
conn.close();
}
}
耦合指的就是程序间的依赖关系,是对程序模块间关联程度的度量。降低耦合的方式:
解耦的思路:
第一步:使用反射来创建对象,而避免使用new关键字。
第二步:通过读取配置文件来获取要创建的对象全限定类名。
2.2 曾经代码中的问题分析
这部分见视频10、项目spring_day01_factory 分析。
//问题如下
//表现层在调用业务层方法的时候,需要new创建业务层对象
AccountService accountService = new AccountServiceImpl();
//业务层在创建持久层方法的时候,需要new创建持久层的对象
private AccountDao accountDao = new AccountDaoImpl();
就像前面说的,凡是设置new对象的,编译期间类之间就会产生依赖关系,这样耦合性太强。
前面提到使用工厂模式可以实现解耦,工厂模式是如何运行的?(视频11,12)
我们使用一个创建Bean对象的工厂BeanFactory类,用来生成service以及dao的Bean对象。这个BeanFactory中使用反射创建service以及dao的对象,避免了编译期的依赖;同时通过配置文件来获取类的全限定类名,使得我们想获得不同对象的时候可以不需要修改代码,而修改配置文件即可。这样便减少了类之间依赖,降低了程序的耦合性。代码如下:
package com.lkj.factory;
/**
* 一个创建Bean对象的工厂
*
* Bean:在计算机英语中,有可重用组件的含义。
* JavaBean:用java语言编写的可重用组件。
* javabean的范围远大于实体类,实体类只是java可重用组件的一部分。
* 我们的业务层service以及持久层dao的类都可以看作可重用组件,也就是javabean。
*
* 这里这个创建Bean对象的工厂,实际上就是创建我们的service和dao对象的。
* -------如何创建service以及dao的对象?
* 第一个:需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 第二个:通过读取配置文件中配置的内容,反射创建对象
*
* 我的配置文件可以是xml也可以是properties
*/
public class BeanFactory
{
/*
首先,由于我们要创建的是AccountServiceImpl以及AccountDaoImpl的对象,因此我们的配置文件bean.properties的内容就是这2个类的全限定类名。
accountService=com.lkj.service.impl.AccountServiceImpl
accountDao=com.lkj.dao.impl.AccountDaoImpl
下面我们读取 bean.properties 文件
*/
//定义一个Properties对象的引用(先不实例化,等到加载类的时候再通过静态代码块实例化)
private static Properties pro;//这个引用要在静态代码块中使用,将其设置为static
//使用静态代码块为Properties对象赋值
static{
try
{
//实例化对象——这里new就产生编译期的依赖,但是这是不可避免的,我们只能减少耦合而无法消除耦合
pro = new Properties();
/*
获取properties文件的流对象
这个时候我们不要使用FileInputStream等读取流来读取properties文件,因为这个时候我们不知道文件名应该写什么。
比如我们写为项目的文件路径 src/bean.properties ,如果是web项目,编译后只有classes目录,没有src,无法使用;
如果我们写为磁盘的绝对路径,这个项目可以找到,但是我们不能保证工程部属后,部属的机器都有相应的盘。
因此,参照之前说的,我们读取文件,要么使用类加载器,要么使用ServletContext对象的getRealPath方法。
*/
//这里使用类加载器读取bean.properties
InputStream rs = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
pro.load(rs);//将流加载到Properties中
}
catch (IOException e)
{
//没有bean.properties文件,任何对象都无法创建,直接抛出错误
throw new ExceptionInInitializerError("初始化Properties失败");
}
}
/**
* 根据bean的名称获取对象——返回Object对象,因为我们不知道要获取哪一个Bean对象,返回Object才能兼容所有类型
* @param beanName
* @return
*/
public static Object getBean(String beanName)
{
Object bean = null;
try
{
//获取Bean对象的全限定类名
String beanPath = pro.getProperty(beanName);
//通过反射获取Bean对象
bean = Class.forName(beanPath).newInstance();
}
catch (Exception e)
{
e.printStackTrace();
}
//如果获取Bean对象失败,那么只会返回null,成功则返回相应对象
return bean;
}
}
当我们使用工厂类BeanFactory来生产Bean对象(AccountService或者AccountDao),此时依赖变为运行时的依赖。比如此时将AccountDaoImpl删除,出现运行时异常:ClassNotFoundException: com.lkj.dao.impl.AccountDaoImpl (这是因为我们没有直接new创建AccountDaoImpl对象 ,而是通过其全限定类名反射创建其对象,在创建的过程中没有使用到这个AccountDaoImpl 的名字,因此缺少这个类的问题会在运行时抛出)。而之前使用new创建Bean对象的时候,我们发现编译期间就会出错(程序直接报错)。
对于上面的代码,我们如果使用工厂多次生产对象,每次生产的对象都不同,也就是生产Bean对象的过程是多例的。
重要!这种多例的模式会出现问题(如视频12所指出的问题):由于每次都生成不同的对象,每个对象都有独立的实例,因此类对象在创建的时候,都会重新初始化成员变量。因此问题中,AccountServiceImpl类的成员变量 i,每次生成AccountServiceImpl对象的时候,都会重新初始化这个i ,因此即使我们每个AccountServiceImpl类的对象都执行 i++ ,每个对象对应的i都是1。
如果我们生产的过程是单例的,既每次生产同一个AccountServiceImpl类对象,那 i 只会初始化一次,并且每次执行saveAccount方法都会 i+1。
我们之前说过,如果使用的是单例对象,当多个线程访问操作类的成员变量的时候,所有的线程都会操作同一个对象的成员变量,比如A线程给成员变量+1,而B线程同时-1,这样便出现线程安全问题。因此我们之前讲Servlet的时候说过,尽量不要定义成员变量。而多例对象则没有这个问题,因为多例对象每个对象都有自己对应的初始化的成员变量。
但是,我们的service与dao中没有需要在方法中进行操作的成员变量,因此我们的service与dao中不存在线程安全问题,他们在创建对象的时候,可以直接创建单例对象。比如我们将上面的 i 创建到saveAccount中,即使是单例对象,多线程调用这个方法,每次 i 都会重新初始化,不会出现多个线程同时操作同一个变量的问题。
我们知道,对象被创建多次,执行效率没有单例对象高。因此我们试图创建service与dao的单例对象。但是BeanFactory中,使用newInstance()创建对象,表示每次都会调用默认构造函数创建对象,因此我们需要对代码进行调整,使得BeanFactory只能newInstance() 一次。这个时候,我们只newInstance一次,如果我们不将这个对象存储,JVM可能将这个对象作为垃圾回收,下次无法使用这个对象,即使创建新的对象,也不是同一个对象。因此newInstance后,应该将这个对象存储起来。如下代码
package com.lkj.factory;
import java.io.IOException;
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的范围远大于实体类,实体类只是java可重用组件的一部分。
* 我们的业务层service以及持久层dao的类都可以看作可重用组件,也就是javabean。
*
* 这里这个创建Bean对象的工厂,实际上就是创建我们的service和dao对象的。
* -------如何创建service以及dao的对象?
* 第一个:需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 第二个:通过读取配置文件中配置的内容,反射创建对象
*
* 我的配置文件可以是xml也可以是properties
*/
public class BeanFactory
{
/*
首先,由于我们要创建的是AccountServiceImpl以及AccountDaoImpl的对象,因此我们的配置文件bean.properties的内容就是这2个类的全限定类名。
accountService=com.lkj.service.impl.AccountServiceImpl
accountDao=com.lkj.dao.impl.AccountDaoImpl
下面我们读取 bean.properties 文件
*/
//定义一个Properties对象的引用(先不实例化,等到加载类的时候再通过静态代码块实例化)
private static Properties pro;//这个引用要在静态代码块中使用,将其设置为static
//定义一个Map,用于存放我们要创建的对象。我们把它称之为容器(同样先不实例化)
private static Map<String,Object> beans;
//使用静态代码块为Properties对象赋值
static{
try
{
//实例化对象——这里new就产生编译期的依赖,但是这是不可避免的,我们只能减少耦合而无法消除耦合
pro = new Properties();
/*
获取properties文件的流对象
这个时候我们不要使用FileInputStream等读取流来读取properties文件,因为这个时候我们不知道文件名应该写什么。
比如我们写为项目的文件路径 src/bean.properties ,如果是web项目,编译后只有classes目录,没有src,无法使用;
如果我们写为磁盘的绝对路径,这个项目可以找到,但是我们不能保证工程部属后,部属的机器都有相应的盘。
因此,参照之前说的,我们读取文件,要么使用类加载器,要么使用ServletContext对象的getRealPath方法。
*/
//这里使用类加载器读取bean.properties
InputStream rs = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
pro.load(rs);//将流加载到Properties中
//实例化容器beans
beans = new HashMap<String, Object>();
//取出配置文件中所有的Key——使用Properties的keys()方法
Enumeration<Object> keys = pro.keys();
//遍历枚举,取出bean.properties中的每一个键,通过键取出值,值既要创建的Bean类的全限定类名
while (keys.hasMoreElements())
{
//nextElemrnt()方法返回Object类型,将其转换为String类型
String key = keys.nextElement().toString();
String beanPath = pro.getProperty(key);
Object value = Class.forName(beanPath).newInstance();//创建Bean类的对象
//把key和value存入容器中——key同样是原来bean.properties中的key,而值是key对应的Bean类的对象
beans.put(key,value);
}
}
catch (Exception e)
{
//没有bean.properties文件,任何对象都无法创建,直接抛出错误
throw new ExceptionInInitializerError("初始化Properties失败");
}
}
/**
* 根据bean的名称获取对象
* 此时,由于静态代码块在初始化的时候,已经将bean.properties中要创建的Bean对象创建并存储到集合beans中,
* 我们只需从beans集合中获取即可。而且由于静态代码块只在BeanFactory进入内存的时候初始化一次,
* 既我们即使多次通过getBean获取相应的对象,也只会获取同一个对象(单例)
* @param beanName
* @return
*/
public static Object getBean(String beanName)
{
return beans.get(beanName);
}
/**
* 根据bean的名称获取对象——返回Object对象,因为我们不知道要获取哪一个Bean对象,返回Object才能兼容所有类型
* @param beanName
* @return
*/
// public static Object getBean(String beanName)
// {
// Object bean = null;
// try
// {
// //获取Bean对象的全限定类名
// String beanPath = pro.getProperty(beanName);
// //通过反射获取Bean对象
// bean = Class.forName(beanPath).newInstance();//每次都会调用默认构造函数创建对象
// }
// catch (Exception e)
// {
// e.printStackTrace();
// }
// //如果获取Bean对象失败,那么只会返回null,成功则返回相应对象
// return bean;
// }
}
在这种情况下,每次获取的都是同一个AccountServiceImpl对象,因此 i 只加载一次。(i定义为类成员)此时多线程访问可能出现线程安全问题(多个线程访问同一个对象)。
如果将 i 定义到saveAccount方法中,线程安全问题便解决。
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候, 让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件, 创建和获取三层对象的类就是工厂。
2.3 IOC的概念和作用
IOC控制反转的涵义(见视频15,文档-2.1.4 控制反转-Inversion Of Control):我们在使用工厂创建对象的时候,将控制权从自己new一个对象,转换给了工厂,工厂获得控制权,为我们生成一个对象,因此这个过程称之为IOC控制反转。这种方式减低了程序间的依赖关系,削减程序间的耦合。
控制反转(Inversion of Control,英文缩写为lOC)把创建对象的权利交给框架(工厂),是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称Dl)和依赖查找(Dependency Lookup)。
明确 ioc 的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。
3、使用 spring 的 IOC 解决程序耦合
明确:IOC不能实现数据库的CRUD,也不能实现表现层的请求参数封装,IOC的作用是削减计算机程序的耦合,必须明确这个概念。
前面已经实现工厂模式解耦,Spring就是使用配置的方式来实现我们刚刚的BeanFactory的代码操作。(准备过程见视频16的解析)
Spring要查看的文档:Spring Framework Documentation,在Spring开发包下面的路径为:spring-framework-5.0.2.RELEASE-dist\spring-framework-5.0.2.RELEASE\docs\spring-framework-reference\index.html
我们已经将其添加至浏览器的移动设备书签。
3.1 Spring环境搭建和入门
具体过程见视频17的解析,我们这里只对重要的细节作记录。(Maven工程只需添加Spring的坐标,不需要导入真正的jar包。)
我们Maven工程中Spring的jar包与使用jar包导入方式Spring的jar包的区别(视频17-3.40)
这部分的注释都在spring_day01_spring_introduce项目(1-3) 以及 spring_day01_bean项目(4),注意查看项目的代码。
3.2 需要注意的细节
1、使用Spring,我们只需要创建配置文件,将要创建对象的类的 全限定类名 以及类名的 唯一标志 存储到配置文件中。使用的时候通过 new ClassPathXmlApplicationContext("配置文件") 获取Spring的核心容器 ApplicationContext ,我们通过唯一标志就可以来获取核心容器中相应的类的对象。
//---------------------------------------------------------
2、ApplicationContext的三个常用实现类:
ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:它是用于读取注解创建容器的。
//---------------------------------------------------------
3、核心容器的两个接口引发出的问题:
ApplicationContext: 单例对象适用 采用此接口
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
BeanFactory: 多例对象使用
它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
注意:BeanFactory 才是 Spring 容器中的顶层接口。ApplicationContext 是它的子接口。
1)我们的service以及dao没有类成员,因此他们不存在线程安全问题,这样我们可以使用单例模式来创建他们的对象。 如果是单例模式创建对象,什么时候创建,都只会创建一个对象,因此当容器ApplicationContext一创建,我们选择立即创建对象。
2)在多例模式中,我们会创建多个对象,如果一开始就创建对象,后面还会创建对象,那我们还不如什么时候使用对象就什么时候创建。
//---------------------------------------------------------
4、spring对bean的管理细节(项目spring_day01_bean)
1) 创建bean的三种方式
第一种方式:使用默认构造函数创建。
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.lkj.service.impl.AccountServiceImpl"></bean>
第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
我们在实际开发过程中,有可能使用到别人写好的类,他们可能存在于jar包中,我们无法对其进行修改,这些类中可能就没有默认构造函数。这种情况下,我们就没办法使用第一种方式来创建jar包中类的对象。
同时,存在这样的的情况,我们要使用普通工厂类中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
如下:我们模拟一个工厂类
//-------------------------------------------------------
//模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
public class InstanceFactory
{
/*
此时这个InstanceFactory是jar包中的类,我们如何获取AccountServiceImpl的对象?
如果我们使用前面的方法创建对象,我们创建的是 InstanceFactory 的对象,而我们想获取的是 InstanceFactory 中getAccountService方法所获取的返回值对象,因此不能用第一种方式创建对象。
第一种方式创建 ——
*/
public AccountService getAccountService(){
return new AccountServiceImpl();
}
}
//--------------------------------------------------------
<bean id="instanceFactory" class="com.lkj.factory.InstanceFactory"></bean> 先获取工厂类的对象
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
这种方式下,我们通过 ApplicationContext 的 getBean("accountService") 方法,通过id="accountService"找到工厂类的名称 factory-bean 以及获取相应对象的方法factory-method,此时第一个<bean>标签已经创建工厂类 factory-bean 的对象,我们通过这个对象就可以调用相应的方法factory-method
来获取这个方法所创建的对象。
实际上,在加载 bean.xml 配置文件的时候,相应的instanceFactory对象已经创建,并且调用getAccountService方法获取 AccountService 对象存放到Spring的容器中。
注意,下面的 factory-bean="instanceFactory" 用来找到上面 <bean> 的 id="instanceFactory",他们的值要相同。
第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
对于第二种方法,如果工厂类中获取对象的方法是静态方法,则应如下设置:
<bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService"></bean>
这种方式下,我们通过 ApplicationContext 的 getBean("accountService") 方法,通过id="accountService"找到工厂类的全限定类名 class="com.itheima.factory.StaticFactory",由于这个工厂类中的 getAccountService 方法是静态的,因此我们没有必要创建工厂类的对象,而是直接通过工厂类的全限定类名,直接调用 getAccountService 方法来获取相应的对象。
2) bean对象的作用范围 调整
首先明确,Spring所创建的Bean对象,默认情况下是单例的。
bean标签的scope属性:
作用:用于指定bean的作用范围 取值: 常用的就是单例的和多例的
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围 (既在web项目的请求范围内,才能通过这个<bean>标签来创建Bean类的对象)
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session(见视频21-4.40解析,如下图1)
3) bean对象的生命周期
bean对象的生命周期
单例对象
出生:当容器 ApplicationContext 创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着。
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收(Spring不知道我们上面时候用完,只能等待JVM的CG回收)
3.3 spring 的依赖注入(参考项目 spring_day01_di)
spring中的依赖注入:Dependency Injection
1、IOC的作用:降低程序间的耦合(依赖关系)。但是程序间的依赖不可能消除,程序间必然存在一些依赖。比如web层调用service,service调用dao。
2、什么是依赖关系:在当前类需要用到其他类的对象。
依赖关系的管理:以后都交给spring来维护。
依赖关系由spring为我们提供,我们只需要在配置文件中说明,既在当前类中告诉Spring我们要使用哪一个类的对象,spring就会为我们提供。
依赖关系的维护:就称之为依赖注入。
能注入的数据:有三类
基本类型和String
其他bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种
第一种:使用构造函数提供
第二种:使用set方法提供
第三种:使用注解提供
依赖注入: Dependency Injection。 它是 spring 框架核心 ioc 的具体实现。我们的程序在编写时, 通过控制反转, 把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。ioc 解耦只是降低他们的依赖关系,但不会消除。 例如:我们的业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系, 在使用 spring 之后, 就让 spring 来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。既,我们在创建一个类对象的时候,同时通过这个类的构造函数,可以给这个类中的成员变量赋值。我们将创建对象并通过构造函数给成员变量赋值的过程交给Spring来完成。创建对象的过程中,当前类与创建对象的类之间形成依赖,这就是依赖注入。
要创建对象的AccountServiceImpl 类
public class AccountServiceImpl implements AccountService
{
/*
1、注入的数据有:name(String)、age(基本数据类型)、Date(Bean类型)
2、如果是经常变化的数据,并不适用于注入的方式。
如果这些数据不常变化,当2个类之间产生依赖关系,可以使用spring的依赖注入,来维护这些数据。
*/
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);
}
}
构造函数注入
<bean id="accountService" class="com.lkj.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="张三">constructor-arg>
<constructor-arg name="age" value="18">constructor-arg>
<constructor-arg name="birthday" ref="now">constructor-arg>
bean>
<bean id="now" class="java.util.Date">bean>
要创建对象的AccountServiceImpl2类(我们需要生成每一个成员变量的setter方法,通过在标签配置这个setter方法来进行赋值)
public class AccountServiceImpl2 implements AccountService
{
//如果是经常变化的数据,并不适用于注入的方式
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);
}
}
set方式注入
<bean id="accountService2" class="com.lkj.service.impl.AccountServiceImpl2">
<property name="name" value="李四">property>
<property name="age" value="21">property>
<property name="birthday" ref="now">property>
bean>
要创建对象的AccountServiceImpl3类
public class AccountServiceImpl3 implements AccountService
{
//下面我们尝试注入复杂类型,采用set方法注入
private String[] myArr;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyArr(String[] myArr) {
this.myArr = myArr;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
public void saveAccount(){
System.out.println(Arrays.toString(myArr));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
set方式注入
<bean id="accountService3" class="com.lkj.service.impl.AccountServiceImpl3">
<property name="myArr">
<array>
<value>AAAvalue>
<value>BBBvalue>
<value>CCCvalue>
array>
property>
<property name="myList">
<list>
<value>AAAvalue>
<value>BBBvalue>
<value>CCCvalue>
list>
property>
<property name="mySet">
<set>
<value>AAAvalue>
<value>BBBvalue>
<value>CCCvalue>
set>
property>
<property name="myMap">
<map>
<entry key="tsetA" value="aaa">entry>
<entry key="testB">
<value>bbbvalue>
entry>
map>
property>
<property name="myProps">
<props>
<prop key="testC">cccprop>
props>
property>
bean>