DI 的优势:解耦
紧耦合:软件组件之间是紧密依赖,很难拆分
松耦合:软件组件之间是松散依赖,随时可以更换
解耦:将软件组件从紧耦合转换为松耦合关系。
利用Spring 管理光头强和工具之间的依赖关系
创建工具接口
/**
* 工具接口
*/
public interface Tool {
}
创建具体的工具 斧子
public class Axe implements Tool, Serializable {
@Override
public String toString() {
return "斧子";
}
}
创建锯
public class Saw implements Tool, Serializable{
@Override
public String toString() {
return "电锯";
}
}
创建工人类型
public class Worker implements Serializable {
private String name; //基本值
private Tool tool; //Bean 对象
private int age; //基本值,
public Worker() {
name = "光头强";
}
public Worker(String name) {
super();
this.name = name;
}
public void setTool(Tool tool) {
this.tool = tool;
System.out.println("setTool:"+tool);
}
public Tool getTool() {
return tool;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("setName:"+name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
System.out.println("setAge:"+age);
}
public void work() { //测试方法
System.out.println(name+"使用"+tool+"砍树");
}
@Override
public String toString() {
return "Worker [name=" + name + ", tool=" + tool + "]";
}
}
在Spring配置文件中利用 IOC/DI 解决依赖关系
<!-- 控制反转 IOC:由Spring创建对象称为控制反转 -->
<bean id="axe" class="day02.Axe"/>
<bean id="saw" class="day02.Saw"/>
<bean id="qiang" class="day02.Worker">
<!-- 依赖注入DI:由Spring帮助建立对象的依赖关系 -->
<!-- spring会自动调用 setTool 方法注入 axe 引用 -->
<property name="tool" ref="saw"/>
</bean>
测试
public class TestCase {
ClassPathXmlApplicationContext ctx;
@Before
public void init() {
ctx=new ClassPathXmlApplicationContext(
"applicationContext.xml");
}
@After
public void destroy() {
ctx.close();
}
@Test
public void testQiang() {
Worker qiang = ctx.getBean("qiang",Worker.class);
qiang.work();
}
}
Spring支持 利用 构造器创建对象:constructor-arg 子元素,其中index="0"用于指定参数在构造器参数的位置。
配置
<bean id="xiong" class="day02.Worker" lazy-init="true">
<!-- 构造器参数注入,也就是调用有参数
构造器创建对象 -->
<constructor-arg index="0" value="熊大"/>
<property name="tool" ref="saw"/>
</bean>
测试
@Test
public void testXiong() {
Worker xiong = ctx.getBean("xiong",Worker.class);
xiong.work();
}
Spring支持自动按照名字注入功能,Spring会自动检查Bean属性和Bean ID的匹配,如果匹配上就自动完成注入
优点:自动注入可以减少XML文件的编写量。
编写配置文件
<bean id="tool" class="day02.Axe" lazy-init="true"/>
<!-- autowire="byName" 自动按照 Bean属性名字和id的
名字 对应关系进行自动注入: bean属性叫tool匹配ID tool
称为按照名字自动装配 autowire="byName"-->
<bean id="tom" class="day02.Worker"
autowire="byName"/>
测试
@Test
public void testTom() {
Worker tom= ctx.getBean("tom",Worker.class);
tom.work();
}
如果测试结果数 tool 属性不为空,则说明自动注入成功了
为了实现按照类型注入,需要利于新的配置文件完成测试:
编写 applicationContext1.xml
<!-- 测试 autowire="byType" 按照类型自动
装配,解决对象的依赖关系 -->
<bean class="day02.Axe"/>
<bean id="tom" class="day02.Worker"
autowire="byType"/>
测试:
public class TestCase2 {
ClassPathXmlApplicationContext ctx;
@Before
public void init() {
ctx=new ClassPathXmlApplicationContext(
"applicationContext2.xml");
}
@After
public void destroy() {
ctx.close();
}
@Test
public void testTom() {
Worker tom= ctx.getBean("tom",Worker.class);
tom.work();
}
}
Spring支持为Bean注入基本类型参数, 这里的基本类型包括:8个基本类,8个包装类型,String类型。
Spring注入基本值时候也是调用的“Bean属性”方法实现的。
配置
<!-- 测试基本值的注入
基本值包含:8个基本类,8个包装类型,String类型 -->
<bean id="andy" class="day02.Worker" lazy-init="true">
<!-- 注入 JavaBean 对象,使用ref属性 -->
<property name="tool" ref="axe"></property>
<!-- 注解基本值,使用value属性 -->
<property name="name" value="熊二"></property>
<property name="age" value="10"></property>
</bean>
Worker类
public class Worker implements Serializable {
private String name; //基本值
private Tool tool; //Bean 对象
private int age; //基本值,
private List<Tool> tools; //注入集合
public Worker() {
name = "光头强";
}
public Worker(String name) {
super();
this.name = name;
}
public void setTool(Tool tool) {
this.tool = tool;
System.out.println("setTool:"+tool);
}
public Tool getTool() {
return tool;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("setName:"+name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
System.out.println("setAge:"+age);
}
public List<Tool> getTools() {
return tools;
}
public void setTools(List<Tool> tools) {
this.tools = tools;
}
public void work() { //测试方法
System.out.println(name+"使用"+tool+"砍树");
}
@Override
public String toString() {
return "Worker [name=" + name + ", tool=" + tool + "]";
}
}
测试:
@Test
public void testAndy() {
Worker andy= ctx.getBean("andy",Worker.class);
andy.work();
}
导入DBCP和MySQL驱动
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
配置:
<!-- 利用Spring 创建 DataSource 连接池实例 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName"
value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/jsd1810db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="10"/>
<property name="initialSize" value="2"/>
</bean>
测试:
@Test
public void testDataSource()
throws SQLException {
//提示: BasicDataSource 实现了 DataSource接口
//所以 使用 DataSource创建变量可以引用
// BasicDataSource 对象实例
DataSource ds = ctx.getBean("dataSource",
DataSource.class);
System.out.println(ds);
Connection conn = ds.getConnection();
//执行SQL版本的Hello World
String sql="select 'Hello World!' as str";
Statement st=conn.createStatement();
ResultSet rs=st.executeQuery(sql);
while(rs.next()) {
System.out.println(rs.getString("str"));
}
rs.close();
st.close();
conn.close();
}
如果能够显示 Hello World 说明能够访问到数据库
当一个对象Bean属性是一个集合时候,可以利用Spring注入一个集合:
Worker类包含集合属性:
public class Worker implements Serializable {
private String name; //基本值
private Tool tool; //Bean 对象
private int age; //基本值,
private List<Tool> tools; //注入集合
public Worker() {
name = "光头强";
}
public Worker(String name) {
super();
this.name = name;
}
public void setTool(Tool tool) {
this.tool = tool;
System.out.println("setTool:"+tool);
}
public Tool getTool() {
return tool;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("setName:"+name);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
System.out.println("setAge:"+age);
}
public List<Tool> getTools() {
return tools;
}
public void setTools(List<Tool> tools) {
this.tools = tools;
}
public void work() { //测试方法
System.out.println(name+"使用"+tool+"砍树");
}
@Override
public String toString() {
return "Worker [name=" + name + ", tool=" + tool + "]";
}
}
配置:
<!-- 为Bean对象注入集合 -->
<bean id="john" class="day02.Worker">
<!-- Bean对象注入 -->
<property name="tool" ref="axe"></property>
<!-- 基本值注入 -->
<property name="name" value="大表哥"/>
<!-- List集合注入 -->
<property name="tools">
<list>
<bean class="day02.Saw"/>
<bean class="day02.Axe"/>
<bean class="day02.Saw"/>
</list>
</property>
</bean>
测试:
@Test
public void testList() {
Worker john = ctx.getBean("john", Worker.class);
System.out.println(john.getTools());
}
如果输出了集合的内容,不为空,则注入成功
Spring提供了读取Properties功能,Properties经常用于存储软件的参数:
在resource文件夹中编写配置文件 jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jsd1810db?useUnicode=true&characterEncoding=UTF-8
username=root
password=root
initSize=3
maxSize=5
配置
<!-- 利用Spring读取Properties文件
location: 位置,定位,这里是文件位置 -->
<util:properties id="jdbc"
location="classpath:jdbc.properties"/>
测试:
@Test
public void testProperties() {
Properties cfg=ctx.getBean("jdbc",
Properties.class);
System.out.println(cfg);
}
Spring表达式的语法与EL表达式类似:
使用Spring 表达式配置数据源:
配置:
<!-- 利用Spring读取Properties文件
location: 位置,定位,这里是文件位置 -->
<util:properties id="jdbc"
location="classpath:jdbc.properties"/>
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource">
<!-- 读取 jdbc的driver属性,将值赋值给
driverClassName 属性-->
<property name="driverClassName"
value="#{jdbc.driver}"/>
<property name="url"
value="#{jdbc.url}"/>
<property name="username"
value="#{jdbc.username}"/>
<property name="password"
value="#{jdbc.password}"/>
<property name="initialSize"
value="#{jdbc.initSize}"/>
<property name="maxActive"
value="#{jdbc.maxSize}"/>
</bean>
测试:
@Test
public void testDS()
throws SQLException {
//提示: BasicDataSource 实现了 DataSource接口
//所以 使用 DataSource创建变量可以引用
// BasicDataSource 对象实例
DataSource ds = ctx.getBean("ds",
DataSource.class);
System.out.println(ds);
Connection conn = ds.getConnection();
//执行SQL版本的Hello World
String sql="select 'Hello World2!' as str";
Statement st=conn.createStatement();
ResultSet rs=st.executeQuery(sql);
while(rs.next()) {
System.out.println(rs.getString("str"));
}
rs.close();
st.close();
conn.close();
}
Spring 提供了一系列注解,用于管理JavaBean。
创建Java类,标注注解
package day02.bean;
@Component //默认的BeanID为 "demoBean"
public class DemoBean implements Serializable{
@Override
public String toString() {
return "DemoBean";
}
}
Spring 会自动查找注解@Componment 找到后自动实例 DemoBean 并且自动分配Bean的ID: demoBean
需要在XML配置文件中开启注解扫描功能。
<context:component-scan base-package="day02.bean"/>
base-package="day02.bean" 指定Spring扫描组件的包范围
测试:
@Test
public void testDemoBean() {
DemoBean bean = ctx.getBean("demoBean",
DemoBean.class);
System.out.println(bean);
}
这些注解功能是一样的,建议按照组件层次使用组件组件。
@Component 通用组件 @Named 通用组件 @Repository 持久层组件 @Service 业务层组件 @Controller 控制器
其中@Named来自 javax.inject 包,需要利用Maven导入
案例:
声明类
@Repository // BeanID 是 demoBean2
public class DemoBean2 {
@Override
public String toString() {
return "DemoBean2";
}
}
测试
@Test
public void testDemoBean2() {
DemoBean2 bean = ctx.getBean("demoBean2",
DemoBean2.class);
System.out.println(bean);
}
如果需要修改默认的BeanID,可以指定BeanID
声明类
@Component("myBean") //自定义BeanID为 myBean
public class TestBean implements Serializable{
@Override
public String toString() {
return "testBean";
}
}
测试
@Test
public void testMyBean() {
TestBean bean = ctx.getBean("myBean",
TestBean.class);
System.out.println(bean);
}
声明类:
@Component
@Scope("prototype") //创建多个对象实例
public class DemoBean3 {
}
测试:
@Test
public void testDemoBean3() {
DemoBean3 bean1 = ctx.getBean("demoBean3",
DemoBean3.class);
DemoBean3 bean2 = ctx.getBean("demoBean3",
DemoBean3.class);
System.out.println(bean1==bean2);
}
@PostConstruct 构造器之后执行方法 @PreDestroy 在销毁之前执行的方法
导入注解包
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
编写类:
@Named
public class Writer implements Serializable{
private PrintWriter out;
//Post 在..以后,Construct:构造器
@PostConstruct //在构造器以后执行 init方法
public void init() throws Exception {
out = new PrintWriter("demo.txt");
System.out.println("init()");
}
public void write(String str) {
out.println(str);
}
//Pre 前, Destroy 销毁
@PreDestroy //在销毁之前执行close()
public void close() {
out.flush();
out.close();
System.out.println("close()");
}
}
测试
@Test
public void testInitDestroy() {
Writer writer = ctx.getBean("writer",
Writer.class);
writer.write("Hello World!");
}