Spring基本实现IOC(xml)

传统的业务处理

DAO层

接口

public interface UserDao {
	void getUser();
}

接口实现类

public class UserDaoImpl implements UserDao {
	public void getUser() {
		System.out.println("获取数据1");
	}
}

Service层

接口

public interface UserService {
	void getUser();
}

接口实现类

public class UserServiceImpl implements UserService {
	private UserDao userdao = new UserDaoImpl();
	public void getUser() {
		userdao.getUser();
	}
}

Controller层

访问Service层

public class User {
	public static void main(String[] args) {
		UserService userService = new UserServiceImpl();
		userService.getUser();
		}
}

回顾MVC

  1. 本例的DAO层Service层Controller层,运用的就是三层架构思想——MVC
  2. 其中的DAO层就是用来做数据持久化的;Service层做业务逻辑对DAO层数据进行处理;Controller层则是请求和接收数据。
  3. 从例子中会发现,Service层返回给Controller层的数据其实就是DAO层的。特别是Service的getUser()方法,完全就是调用DAO层的getUser()方法。
  4. 之所以不让Controller层直接获取DAO层的数据进行业务逻辑操作。其目的就是为了保证用户数据安全

传统过程中暴露出来的问题

当客户需求发生改变时

比如:当用户想要访问的dao层数据发生改变时

  1. 此时,dao层必须增加业务代码。这个必不可免

dao层增加的代码:

又一个接口实现类:

public class User_01_DaoImpl implements UserDao {
	public void getUser() {
		System.out.println("获取数据2");
	}
}
  1. 同时Service层的代码也要进行改动,这就不太方便了。

修改后的Service层接口实现类代码:

public class UserServiceImpl implements UserService {
	private UserDao userdao = new User_01_DaoImpl();
	public void getUser() {
		userdao.getUser();
	}
}
  • 这与起初的代码相比,仅仅是修改了new对象时指向的类型
  • 但是用户的需求每更改一次,就要修改一次业务代码(Service层)。
  • 如果程序代码量十分大,修改一次的成本代价就十分昂贵。

解决思路

  1. 上面的代码。在service层中程序是主动创建对象,控制权在程序员手上。
  2. 应该把对象的创建转移给第三方。使用户拥有主动权。

将原本Service层的实现类的代码修改为:

public class UserServiceImpl implements UserService {
	private UserDao userdao;
	
	//利用set进行动态实现值的注入!
	public void setUserDao(UserDao userdao) {
		this.userdao = userdao;
	}
	
	public void getUser() {
		userdao.getUser();
	}
}

此时用户使用时只需调用UserServiceImpl 类对象的setUserDao()方法,动态的传入想要的DAO层对象:

public class User {
	public static void main(String[] args) {
		UserService userService = new UserServiceImpl();
		//之前,程序是主动创建对象!控制权在程序员手上
		//使用set注入后,程序不再具有主动性,而是变成了被动的接受对象
		//留接口,用什么自己去调
		((UserServiceImpl)userService).setUserDao(new UserDaoImpl());
		userService.getUser();
		}
}

注意:

  1. 这仅仅是一个思路,因为代码中出现了Controller层直接访问DAO层的现象,这是绝对不允许的。
  2. 下面来看看Spring是如何通过IOC正确合理的实现这个思路的——Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。说白了,对象由Spring来创建


Ioc的业务处理

简单描述IOC

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时从Ioc容器中取出需要的对象。

零配置: 采用XML配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入。

IOC的具体实现

  1. 先写一个实体类
public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}
  1. 写一个bean配置的xml文件(核心内容就是中间的bean标签,其他的部分去Spring官网IOC部分粘取)
<?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="hello" class="pojo.Hello">
        <property name="str" value="数值"></property>
    </bean>

</beans>
  1. 获取实体类对象并去使用。

声明:

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

本行代码取自官网,可传多个xml文件作为参数

public class HelloTest {
    public static void main(String[] args) {
    //ApplicationContext是一个接口,多态思想。另本行内容同样去Spring官网粘取
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello)context.getBean("hello");
        System.out.println(hello.toString());//Hello{str='数值'}
    }
}

此时我们发现,并没有去new对象,但是却可以直接取用Hello类的对象。

解读上面代码:(xml部分)
上面代码的第二步,xml配置文件部分。(此过程就可称为控制反转
在这里插入图片描述

简单总结

Hello对象是谁创建的?

  • hello对象是由Spring创建的

Hello对象的属性是怎么设置的?
+hello对象的属性是由Spring容器设置的

控制

  • 谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。

反转

  • 程序本身不创建对象,而变成被动的接收对象。

依赖注入

  • 就是利用set方法来进行注入的(说真的,不太理解)
  • 看下面的demo!

依赖注入补充

Person实体类

  • 上面说到通过set注入,所以实体类中的set方法必不可少
public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

Pet实体类

  • pet(宠物)离不开主人,因此有一个Person类型的master
public class Pet {
    private String name;
    private int age;
    private Person master;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person getMaster() {
        return master;
    }

    public void setMaster(Person master) {
        this.master = master;
    }

    @Override
    public String toString() {
        return "Pet{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", master=" + master +
                '}';
    }
}

xml配置

  • 首先要明确,一个<bean></bean>就相当于一个类的对象
  • 通过<property>标签的name和value为类中属性赋值的前提条件就是类中有set方法
  • 上面提到<property>标签的name和value,此处又多了一个ref,ref是为当前类注入所需的对象。其前提也是得有对应的set方法。
  • 可以简单理解为value和ref都是为name属性赋值的,只不过value是为基本类型赋值ref是引用Spring中已经创建好的对象(其他bean)
  • 一个bean的id可以通过ref注入到另一个bean中。比如此处将Person的bean的id注入到了Pet的bean中。相当于给了Pet类中Person类型的master属性一个Person对象。
  • 兜了这么大一圈,目的还是为了不去自己new 对象
	<bean id="person"  class="pojo.Person" >
        <property name="name" value="主人1"></property>
    </bean>

    <bean id="pet" class="pojo.Pet">
        <property name="master" ref="person"></property>
    </bean>

测试代码

  • 通过获取Person类对象,通过setName()方法为name属性赋值。
  • 此时,xml中,value="主人1"被“窦哥”覆盖。
public class PetTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Pet pet = (Pet)context.getBean("pet");
        Person person = (Person)context.getBean("person");
        person.setName("窦哥");
        pet.setMaster(person);
        System.out.println(pet.getMaster());
    }
}

IOC容器是如何创建对象的?

无参构造

默认情况下是通过类中的无参构造创建的,在加载配置文件(xml文件)时,容器中管理的对象就已经初始化了。最简单的检验方法就是在类的无参构造中输出一句话,当获取IOC容器对象后,执行代码就会输出无参构造中打印的内容。

有参构造

无参构造检验环境就是在原有类中声明有参构造,并且不显式的声明无参构造,此时xml对应的bean就会报错。以下是三种有参构造创建对象的方法。

下标赋值创建

<!--    下标赋值创建对象-->
   <bean id="hello" class="pojo.Hello">
       <constructor-arg index="0" value="str_01"/>
       <constructor-arg index="1" value="str_02"/>
       ................
   </bean>

此处下标为有参构造参数的下标,value为对应参数的值,本例中默认用的String类型的参数。

类型创建。(不建议使用)

<!--    通过类型创建对象-->
   <bean id="hello" class="pojo.Hello">
       <constructor-arg type="java.lang.String" value="str_01"/>
       <constructor-arg type="int" value="6"/>
   </bean>

此处第一个参数为String类型的,第二个为int类型的
注意,包装类必须用全限定名

参数名创建(最容易让人接受)

<!--    通过参数名创建对象-->
   <bean id="hello" class="pojo.Hello">
       <constructor-arg name="str" value="Hello"/>
       <constructor-arg name="str2" value="6"/>
   </bean>

此处name为有参构造形参数名字,value为对应参数的值。

扩充(不重要,可跳过)

Spring相对重要且常用的是注解开发,而且今后常用的是SpringBoot,所以以下指示了解即可。

  1. 别名在这里插入图片描述
  2. import(在一个xml文件中导入其他xml文件)在这里插入图片描述
  3. 依赖注入
    3.1 构造器注入
    3.2 Set方式注入(重点掌握set注入)在这里插入图片描述
    在这里插入图片描述
    3.3 拓展方式注入(c命名空间注入、p命名空间注入。知道就行)
  4. bean作用域在这里插入图片描述
    这个作用域问题就是IOC容器创建的对象个数。默认是单例的(singleton)。如下所示
public class HelloTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello)context.getBean("hello");
        Hello hello1 = (Hello)context.getBean("hello");
        System.out.println(hello==hello1);//true
    }
}

可以在xml文件中修改配置(上表中除了singleton和prototype,其他只能在web开发中使用)

  <bean id="hello" class="pojo.Hello" scope="singleton">
        <property name="str" value="Hello" ></property>
    </bean>
  1. bean的自动装配在这里插入图片描述

    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值