springIOC与DI

spring下载与开发

spring3.x 版本主要是整合hibernate3,如果想要整合hibernate5.x可以使用spring4.x

如何从spring官网下载jar包

ioc

什么是ioc

简单理解ioc(inverse of control)就是对象的创建方式由new转而交给spring,这里反转的意思就是对象的创建方式由创建到->直接拿

平时我们创建一个对象的时候使用的new,但是使用spring之后,我们获取一个对象就不是使用new,而是从容器中拿,所以说创建对象的方式被反转了

ioc的底层实现原理

原始创建对象的方式

java接口代码

package top.twolovelypig.dao;
public interface IUserDAO {
	public void save();
}

实现类代码

package top.twolovelypig.dao;
public class JdbcUserDAO implements IUserDAO{
	@Override
	public void save() {
		System.out.println("保存学生的代码执行了");
	}
}

测试代码

package top.twolovelypig.test;
import org.junit.Test;
import top.twolovelypig.service.IUserDAO;
import top.twolovelypig.service.UserDAO;
public class TestUser {
	@Test
	public void save() {
		//原始创建对象的方式
		IUserDAO obDao = new JdbcUserDAO();
		obDao.save();
	}
}

上面dao中有一个save方法是通过jdbc方式来实现的,现在想要修改为通过hibernate方式来实现,就是再增加一个hibernateUserDAO接口,但是在调用的时候需要修改很多的代码,原来创建的JdbcUserDAO现在都需要修改为hibernateUserDAO。显然这种代码的扩展方式不够好。

通过工厂模式优化

上面的方式之所以想要修改一个功能就需要修改很多的代码就是因为实现类与接口直接耦合性太强,此时有一个解决办法就是不让接口与实现类直接接触,可以在二者中间插入一个工厂,将所有的创建对象的代码放入到该工厂当中。虽然这种方式对于上面的代码来说是有了改进,但是接口和工厂之间依然是有耦合的,此时可以使用工厂+反射+配置文件来实现程序解耦合。

进一步优化-ioc实现原理

[外链图片转存失败(img-88sMZMcN-1563369294730)(https://raw.githubusercontent.com/GWei11/CloudPicture/master/data/20190428221551.png)]

上面可以看到ioc的实现原理其实就是使用工厂+反射+配置文件三者结合来实现的。

对于spring的ioc注意功能就是将实现类以及接口(主要是实现类)交给spring来管理。

使用spring的配置文件
<?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">
	<bean id="userDao" class="top.twolovelypig.dao.UserDAO"></bean>
</beans>

测试代码

public class TestUser {
	@Test
	public void testSave() {
		//原始创建对象的方式
		/*IUserDAO obDao = new UserDAO();
		obDao.save();*/

		//使用ioc的方式
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		IUserDAO objUserDao = (UserDAO)applicationContext.getBean("userDao");
		objUserDao.save();
	}
}

Spring工厂

spring的工厂主要分为两类:

  • BeanFactory:旧版本的工厂类,在调用getBean()方法的时候才会生成类的实例。
  • ApplicationContext:新版本的工厂类,加载配置文件的时候就会将Spring管理的类都实例化,主要有两个实现类。
    • ClassPathApplicationContext:加载类路径下的配置文件
    • FileSystemXmlApplicationContext:加载文件系统下的配置文件

bean的相关配置

bean的生命周期

<bean id="userDao" class="top.twolovelypig.dao.UserDAO" init-method="init" destroy-method="destroy"></bean>

在bean标签中主要是有init-methoddestroy-method两个属性来配置初始化方法和销毁的方法,比如这里配置了init-method=“init”,也就是再UserDAO中需要有一个init方法,当该类被初始化的时候这个方法就会执行,同样的如果配置了销毁的方法,那么当applicationContext对象执行close()方法时销毁方法就会被执行。

bean的作用范围的配置

Scope: Bean的作用范围

  • singleton:默认值,spring会采用单例模式创建这个对象
  • prototype:多例模式(Struts2spring整合的时候会使用到)
  • request:应用在web项目中,spring创建该类后,将这个类存入到request范围中
  • session:应用在web项目中,spring创建该类后,将该类存入到session范围中
  • globalsession:应用在web项目中,必须在porlet(比如登录百度账号,然后在登录百度网盘时就不需要输入账户和密码就可以直接登录,像这种存在子域的关系就是porlet环境),但是如果没有这种环境,就相当于是session

DI(依赖注入)

依赖注入的前提是必须有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来。有两种方式。

构造方法注入

普通类型

Bean

package top.twolovelypig.demo1;
public class Car {
	private String name;
	private double price;
	public Car(String name, Double price) {
		this.name = name;
		this.price = price;
	}
    //重写tostring
}

Bean的配置

<bean id="car" class="top.twolovelypig.demo1.Car">
	<constructor-arg name="name" value="法拉利"></constructor-arg>
	<constructor-arg name="price" value="10000001"></constructor-arg>
</bean>

对象类型

Bean

package top.twolovelypig.demo1;
public class Person {
	private String name;
	private Car car;
	public Person(String name, Car car) {
		super();
		this.name = name;
		this.car = car;
	}
	//重写tostring
}

Bean的配置

<bean id="car" class="top.twolovelypig.demo1.Car">
    <constructor-arg name="name" value="法拉利"></constructor-arg>
    <constructor-arg name="price" value="10000001"></constructor-arg>
</bean>
<bean id="person" class="top.twolovelypig.demo1.Person">
    <constructor-arg name="name" value="张三"></constructor-arg>
    <!--使用构造方法含有对象的时候就不是使用value而是使用ref,后面接的是配置那个对象的id值-->
    <constructor-arg name="car" ref="car"></constructor-arg>
</bean>

set方法注入

普通类型

使用set方法注入就不需要构造器了,但是需要添加set方法。

package top.twolovelypig.demo1;
public class Car {
	private String name;
	private double price;
	public void setName(String name) {
		this.name = name;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "Car [name=" + name + ", price=" + price + "]";
	}
}

<bean id="car" class="top.twolovelypig.demo1.Car">
    <property name="name" value="奔驰"></property>
    <property name="price" value="10000"></property>
</bean>

对象类型

package top.twolovelypig.demo1;
public class Person {
	private String name;
	private Car car;
	public void setName(String name) {
		this.name = name;
	}
	public void setCar(Car car) {
		this.car = car;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", car=" + car + "]";
	}
}

<bean id="person" class="top.twolovelypig.demo1.Person">
    <property name="name" value="张三"></property>
    <property name="car" ref="car"></property>
</bean>

注:无论是set方法注入还是构造器注入,对于普通属性都是使用name与value即可,对于对象类型后面的value就需要更换为ref,ref的值为该对象在配置文件里面配置的bean的id。

P命名空间方式注入

可以通过引入p名称空间完成属性的注入:

写法

  • 普通属性: p:属性名=“值”>
  • 对象属性: p:属性名-ref=“值”

使用步骤

  • 添加p命名空间

    xmlns:p="http://www.springframework.org/schema/p"
    
    

    添加也是很简单的,一开始肯定是有bean命名空间的,我们赋值一份,只需要将开始的xmlns修改为xmlns:p,然后将最后的beans修改为p即可.

  • 按照上述的写法写配置文件

    <bean id="car" class="top.twolovelypig.demo1.Car">
        <property name="name" value="奔驰"></property>
        <property name="price" value="10000"></property>
    </bean>
    <!-- <bean id="person" class="top.twolovelypig.demo1.Person">
      <property name="name" value="张三"></property>
      <property name="car" ref="car"></property>
     </bean> -->
    <bean id="person" class="top.twolovelypig.demo1.Person" p:car-ref="car" p:name="张三"></bean>
    
    

    SpEL(Spring expression language)注入

    语法格式

    #{SpEL}

    基本属性

    <bean id="car" class="top.twolovelypig.demo1.Car">
        <property name="name" value="奔驰"></property>
        <property name="price" value="10000"></property>
    </bean>
    <!-- <bean id="person" class="top.twolovelypig.demo1.Person">
      <property name="name" value="张三"></property>
      <property name="car" ref="car"></property>
     </bean> -->
    <bean id="person" class="top.twolovelypig.demo1.Person">
        <property name="name" value="#{'张三'}"></property>
        <property name="car" value="#{car}"></property>
    </bean>
    
    

    注意点:

    • 无论是基本属性还是对象属性都是使用value而不是使用ref
    • 如果是字符串需要使用单引号括起来,如果不是就不用单引号

    通过计算得到值

    上面只是基本的属性和对象,其余使用SpEl的一个好处是很灵活,value里面的值可以是表达式也可以是某一个类的属性或者方法,比如现在又如下类:

    public class getCarInfo{
        public String name;
        
        public void setName(String name){
            this.name = name;
        }
        
        public String getName(){
            return this.name;
        }
        
        public double getPrice(){
            return Math.random() * 3000;
        }
    }
    
    

    现在继续修改上面的配置文件:

    <bean id="carInfo" class="top.twolovelypig.demo1.CarInfo">
        <property name="name" value="奔驰"></property>
    </bean>
    <bean id="person" class="top.twolovelypig.demo1.Person">
        <property name="name" value="#{carInfo.name}"></property>
        <property name="car" value="#{carInfo.getPrice()}"></property>
    </bean>
    
    

    可以看到其value值是可以通过其他类的属性或者方法来赋值的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值