【简单说】SpringIOC

通过一个简单的案例来认识什么是控制反转,为什么要使用SpringIOC容器

业务逻辑层Dao,定义一个UserDao接口

package com.ctb.dao;

public interface UserDao {

    // 获取用户
    void getUser();
}

接下来写每个不同的UserDao的具体实现
普通方式:

package com.ctb.dao.impl;

import com.ctb.dao.UserDao;

public class UserDaoImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("普通方式获取用户");
    }
}

使用Mysql方式:

package com.ctb.dao.impl;

import com.ctb.dao.UserDao;

public class UserDaoMysqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("使用Mysql获取数据");
    }
}

使用Oracle方式:

package com.ctb.dao.impl;

import com.ctb.dao.UserDao;

public class UserDaoOracleImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("使用Oracle获取数据");
    }
}

接下来写的是Service层接口以及具体实现

package com.ctb.service;

public interface UserService {
    public void getUser();
}
package com.ctb.service.impl;
import com.ctb.dao.UserDao;
import com.ctb.service.UserService;
public class UserServiceImpl implements UserService {
//    private UserDao userDao = new UserDaoImpl();
//    private UserDao userDao = new UserDaoMysqlImpl();
    private UserDao userDao = new UserDaoOracleImpl();

    @Override
    public void getUser() {
        userDao.getUser();
    }
}

最后定义测试类:

public class MyTest {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        userService.getUser();
    }
}
结论:可以看到每次想调用不同的dao的时候都需要在service中进行修改,可以说是非常复杂的,如果说提供了用户可能用到的dao,当用户想调用哪个自己说明,就可以直接调用,那不就不用再让我们进行修改了吗,以下的方式就是说明控制反转

重新修改Service的实现类:

package com.ctb.service.impl;

import com.ctb.dao.UserDao;
import com.ctb.service.UserService;

public class UserServiceImpl implements UserService {


    private UserDao userDao;

    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}

重新完成测试类,测试类把需要的方式告诉Service,再通过Service进行调用:

package com.ctb.test;

import com.ctb.dao.impl.UserDaoImpl;
import com.ctb.dao.impl.UserDaoMysqlImpl;
import com.ctb.dao.impl.UserDaoOracleImpl;
import com.ctb.service.impl.UserServiceImpl;

public class MyTest {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        userService.setUserDao(userDaoImpl);
        userService.getUser();

        System.out.println("--------------");

        UserDaoMysqlImpl userDaoMysql = new UserDaoMysqlImpl();
        userService.setUserDao(userDaoMysql);
        userService.getUser();

        System.out.println("--------------");

        UserDaoOracleImpl userDaoOracle = new UserDaoOracleImpl();
        userService.setUserDao(userDaoOracle);
        userService.getUser();
    }
}
结论:springIOC指的是控制反转,所谓的控制反转就是指一开始我来创建自己所需要的对象,后面反转为由别人来控制并给予我所需要的对象

控制反转的作用

  • 管理对象的创建和依赖关系的维护
  • 托管了类的产生过程
  • 解耦,在面向对象的软件系统中,底层实现可能有多个对象组成如图所示
    在这里插入图片描述
    一旦某一个对象出现了问题,那么其他对象肯定回有所影响,这就是耦合性太高的缘故,但是对象的耦合关系是无法避免的,也是必要的。随着应用程序越来越庞大,对象的耦合关系可能越来越复杂,经常需要多重依赖关系,因此,无论是架构师还是程序员,在面临这样的场景的时候,都需要减少这些对象的耦合性。
    在这里插入图片描述

SpringIOC的使用

下面介绍了SpringIOC的各种使用方式,给出案例进行说明,在下面每个案例操作之前,需要创建maven项目,并导入spring配置

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
  1. 通过bean的id来获取IOC容器中的对象
    定义一个Animal的bean,给它创建3个属性(名字,颜色,腿的数量),给它创建set,get,toString方法
package com.ctb.bean;

public class Animal {

    private String name;

    private String color;

    private int legsNum;

    public Animal() {
    }

    public Animal(String name, String color, int legsNum) {
        this.name = name;
        this.color = color;
        this.legsNum = legsNum;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getLegsNum() {
        return legsNum;
    }

    public void setLegsNum(int legsNum) {
        this.legsNum = legsNum;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", legsNum=" + legsNum +
                '}';
    }
}

配置ioc2.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">

    <bean id="animal" class="com.ctb.bean.Animal">
        <property name="name" value="二哈"></property>
        <property name="color" value="黑白"></property>
        <property name="legsNum" value="4"></property>
    </bean>

</beans>

测试类:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");
        Animal animal = (Animal)context.getBean("animal"); //在ioc2.xml中给animals的id定义为animal,此行通过id来获取bean
        System.out.println(animal);
    }
}

测试结果:
在这里插入图片描述
2. 通过bean的类型来获取IOC容器中的对象
同样是上面的配置,只用修改测试类

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");
        Animal animal = (Animal)context.getBean(Animal.class);
        System.out.println(animal);
    }
}

注意:因为在ioc2.xml中创建的是只有一个Animal类型的bean对象,所以可以使用这种方式进行获取,如果在ioc2.xml中创建多个bean对象,需要修改方式如下:
配置文件如下:

<bean id="animal" class="com.ctb.bean.Animal">
        <property name="name" value="二哈"></property>
        <property name="color" value="黑白"></property>
        <property name="legsNum" value="4"></property>
    </bean>

    <bean id="animal2" class="com.ctb.bean.Animal">
        <property name="name" value="阿拉斯加"></property>
        <property name="color" value="棕白"></property>
        <property name="legsNum" value="4"></property>
    </bean>

测试类:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");
        Animal animal = (Animal)context.getBean("animal",Animal.class);
        Animal animal2 = (Animal)context.getBean("animal2",Animal.class);
        System.out.println(animal);
        System.out.println(animal2);
    }
}
  1. 通过构造器给bean对象赋值
    使用该方式的时候,需要先给bean类补充构造方法
public Animal(String name, String color, int legsNum) {
        this.name = name;
        this.color = color;
        this.legsNum = legsNum;
    }
<bean id="animal3" class="com.ctb.bean.Animal">
        <constructor-arg name="name" value="金毛"></constructor-arg>
        <constructor-arg name="color" value="金色"></constructor-arg>
        <constructor-arg name="legsNum" value="4"></constructor-arg>
    </bean>

    <!-- 使用构造器创建bean的时候可以省略name属性,但是要按照构造方法中参数的顺序来赋值 -->
    <bean id="animal4" class="com.ctb.bean.Animal">
        <constructor-arg value="柴犬"></constructor-arg>
        <constructor-arg value="棕白"></constructor-arg>
        <constructor-arg value="4"></constructor-arg>
    </bean>
    
    <!-- 或者使用index来决定每个值的位置 -->
    <bean id="animal5" class="com.ctb.bean.Animal">
        <constructor-arg value="黑色" index="1"></constructor-arg>
        <constructor-arg value="4" index="2"></constructor-arg>
        <constructor-arg value="藏獒" index="0"></constructor-arg>
    </bean>

同时也会存在构造方法参数个数相同的情况,如果参数相同但是也不是用指定的name,那么可以使用以下方式
添加两个构造方法:

	public Animal(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public Animal(String name, int legsNum) {
        this.name = name;
        this.legsNum = legsNum;
    }
<!-- 通过type来指定传入的参数类型-->
    <bean id="animal6" class="com.ctb.bean.Animal">
        <constructor-arg value="羊驼"></constructor-arg>
        <constructor-arg value="白色" type="java.lang.String"></constructor-arg>
    </bean>

    <!-- 注意使用int的使用,在type中找不到包,所以可以通过以下方式 -->
    <bean id="animal7" class="com.ctb.bean.Animal">
        <constructor-arg  value="公鸡"></constructor-arg>
        <constructor-arg  value="2" type="int" index="1"></constructor-arg>
    </bean>
  1. 通过命名空间为bean赋值,简化配置文件中属性声明的写法
    使用p-namespace进行更简洁的XML配置
    在使用之前先要导入配置
 xmlns:p="http://www.springframework.org/schema/p"
<bean id="animal8" class="com.ctb.bean.Animal" p:name="鸭子" p:color="白色" p:legsNum="2"></bean>
  1. 为复杂类型进行赋值操作
    创建一个食物类:
public class Food {

    String name;

    public Food() {
    }

    public Food(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

创建一个place的类:

public class Place {

    private String name;

    private int size;

    public Place() {
        //System.out.println("创建Place的bean");
    }

    public String getName() {
        return name;
    }

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

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }
    
     @Override
    public String toString() {
        return "Place{" +
                "name='" + name + '\'' +
                ", size=" + size +
                '}';
    }
}

重新创建animal类:

package com.ctb.bean;

import java.util.*;

public class Animal {

    private String name;

    private String[] color;

    private int legsNum;

    private Food food;

   private List<Place> placeList;

   private Set<Integer> size;

   private Map<String,Object> maps;

   private Properties properties;

    public Animal() {
    }

    public Animal(String name, String[] color, int legsNum, Food food, List<Place> placeList, Set<Integer> size, Map<String, Object> maps, Properties properties) {
        this.name = name;
        this.color = color;
        this.legsNum = legsNum;
        this.food = food;
        this.placeList = placeList;
        this.size = size;
        this.maps = maps;
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", color=" + Arrays.toString(color) +
                ", legsNum=" + legsNum +
                ", food=" + food +
                ", placeList=" + placeList +
                ", size=" + size +
                ", maps=" + maps +
                ", properties=" + properties +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public String[] getColor() {
        return color;
    }

    public void setColor(String[] color) {
        this.color = color;
    }

    public int getLegsNum() {
        return legsNum;
    }

    public void setLegsNum(int legsNum) {
        this.legsNum = legsNum;
    }

    public Food getFood() {
        return food;
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public List<Place> getPlaceList() {
        return placeList;
    }

    public void setPlaceList(List<Place> placeList) {
        this.placeList = placeList;
    }

    public Set<Integer> getSize() {
        return size;
    }

    public void setSize(Set<Integer> size) {
        this.size = size;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

通过ioc2.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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建外部对象 -->
    <bean id="food" class="com.ctb.bean.Food">
        <property name="name" value="meat"></property>
    </bean>

    <bean id="place1" class="com.ctb.bean.Place">
        <property name="name" value="Africa"></property>
    </bean>

    <!--给复杂类型的赋值都在property标签内进行-->
    <bean id="animal" class="com.ctb.bean.Animal">
        <property name="name">
            <!--赋空值-->
            <null></null>
        </property>
        <!--给数组赋值-->
        <property name="color">
            <array>
                <value>黄色</value>
                <value>白色</value>
            </array>
        </property>
        <property name="legsNum" value="4"></property>
        <!--通过ref引用其他对象,引用外部bean-->
        <property name="food" ref="food"></property>
        <!--引用内部bean-->
        <!-- <property name="address">
             <bean id="food" class="com.ctb.bean.Food">
        <property name="name" value="肉"></property>
         </bean>
         </property>-->
        <!--为list赋值-->
        <property name="placeList">
            <list>
                <!--内部bean-->
                <bean id="place2" class="com.ctb.bean.Place">
                    <property name="name" value="China"></property>
                </bean>
                <!--外部bean-->
                <ref bean="place1"></ref>
            </list>
        </property>
        <!--给set赋值-->
        <property name="size">
            <set>
                <value>100</value>
                <value>200</value>
            </set>
        </property>
        <!--给map赋值-->
        <property name="maps">
            <map>
                <entry key="appearance" value="cute"></entry>
                <entry key="place" value-ref="place1"></entry>
                <entry key="food3">
                    <bean class="com.ctb.bean.Food">
                        <property name="name" value="apple"></property>
                    </bean>
                </entry>
            </map>
        </property>
        <!--给property赋值-->
        <property name="properties">
            <props>
                <prop key="aaa">aaa</prop>
                <prop key="bbb">222</prop>
            </props>
        </property>
    </bean>


</beans>

测试类:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");
        Animal animal16 = context.getBean("animal",Animal.class);
        System.out.println(animal16);
    }
}

测试结果:
在这里插入图片描述

  1. 继承关系bean的配置
<bean id="animal" class="com.ctb.bean.Animal">
        <property name="name" value="二哈"></property>
        <property name="color" value="黑白"></property>
        <property name="legsNum" value="4"></property>
    </bean>

    <!-- 我家的二哈出去沾花惹草了,生出了只杂狗,使用parent来指定bean的配置信息继承哪个bean -->
    <bean id="animal9" class="com.ctb.bean.Animal" parent="animal">
        <property name="name" value="杂狗"></property>
    </bean>

测试类:

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");
        Animal animal9 = (Animal)context.getBean("animal9",Animal.class);
        System.out.println(animal9);
    }

在这里插入图片描述
7. bean对象创建的依赖关系
删除之前所有创建的bean,只用创建两个bean

	<bean id="animal10" class="com.ctb.bean.Animal"></bean>
    <bean id="place" class="com.ctb.bean.Place"></bean>

在两个类的无参构造方法中填入打印字段
测试类:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");
    }
}

测试结果:
在这里插入图片描述
当我修改配置为:

<bean id="animal10" class="com.ctb.bean.Animal" depends-on="place"></bean>
    <bean id="place" class="com.ctb.bean.Place"></bean>

测试结果:
在这里插入图片描述
可以通过depends-on来决定创建bean的顺序

  1. bean的作用域控制,是否是单例
<bean id="animal11" class="com.ctb.bean.Animal" scope="singleton">
    </bean>

    <bean id="animal12" class="com.ctb.bean.Animal" scope="prototype">
    </bean>
		Animal animal11 = (Animal)context.getBean("animal11",Animal.class);
        Animal animal11_1 = (Animal)context.getBean("animal11",Animal.class);
        System.out.println(animal11 == animal11_1);

        Animal animal12 = (Animal)context.getBean("animal11",Animal.class);
        Animal animal12_1 = (Animal)context.getBean("animal11",Animal.class);
        System.out.println(animal12 == animal12_1);

测试结果:
在这里插入图片描述

  1. 利用工厂模式创建bean对象
    除了上述的提供反射得到对应的bean创建方式,还可以通过工厂模式进行对象的创建
    静态工厂:工厂本身不需要创建对象,只是通过调用类的静态方法来创建
    创建动物类的工厂
public class AnimalStaticFactory {
    public static Animal createAnimal(String name){
        Animal animal = new Animal();
        animal.setName(name);
        return animal;
    }
}
<!-- 通过factory-method来指定工厂方法 -->
    <bean id="animal13" class="com.ctb.factory.AnimalStaticFactory" factory-method="createAnimal">
        <!--constructor-arg:可以为方法指定参数-->
        <constructor-arg value="加菲猫"></constructor-arg>
    </bean>

实例工厂:工厂本身需要创建对象

public class AnimalFactory {

    public Animal createAnimal(String name){
        Animal animal = new Animal();
        animal.setName(name);
        return animal;
    }
}
<!--创建实例工厂类-->
    <bean id="AnimalFactory" class="com.ctb.factory.AnimalFactory"></bean>
    <!-- factory-bean:指定使用哪个工厂实例   factory-method:指定使用哪个工厂实例的方法 -->
    <bean id="animal14" class="com.ctb.bean.Animal" factory-bean="AnimalFactory" factory-method="createAnimal">
        <constructor-arg value=""></constructor-arg>
    </bean>
  1. 实现FactoryBean接口来创建对象
    FactoryBean是Spring规定的一个接口,当前接口的实现类,Spring都会将其作为一个工厂,但是在ioc容器启动的时候不会创建实例,只有在使用的时候才会创建对象
public class MyFactoryBean implements FactoryBean<Animal> {

    // 返回创建的对象
    public Animal getObject() throws Exception {
        Animal animal = new Animal();
        animal.setName("ctb");
        return animal;
    }

    // 返回创建的类型
    public Class<?> getObjectType() {
        return Animal.class;
    }

    // 返回创建对象是否单例
    public boolean isSingleton() {
        return false;
    }
}
<bean id="myFactoryBean" class="com.ctb.factory.MyFactoryBean"></bean>
  1. bean对象的初始化和销毁方法
    在Animal类中加入init,destory方法
    如果bean是单例,容器在启动的时候会创建好,关闭的时候会销毁创建的bean,如果bean是多例,获取的时候创建对象,销毁的时候不会有任何的调用,destory在ApplicationContext关闭的时候才会调用
public void init(){
        System.out.println("对象被初始化");
    }

    public void destory(){
        System.out.println("对象被销毁");
    }
    <bean id="address" class="com.ctb.bean.Animal" init-method="init" destroy-method="destory"></bean>

测试代码:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc2.xml");

        Animal animal15 = context.getBean("animal15",Animal.class);
        System.out.println(animal15);
        //applicationContext没有close方法,需要使用具体的子类
        ((ClassPathXmlApplicationContext)context).close();
    }
}

测试结果:
在这里插入图片描述
12. 配置bean对象初始化方法的前后处理方法
如果想在bean对象初始化方法的前后进行相关操作,那么需要实现BeanPostProcessor接口

public class MyBeanPostProcessor implements BeanPostProcessor {

    //在初始化方法调用之前执行
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization:"+beanName+"调用初始化前置方法");
        return bean;
    }

    //在初始化方法调用之后执行
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization:"+beanName+"调用初始化后缀方法");
        return bean;
    }
}
<bean id="myBeanPostProcessor" class="com.ctb.factory.MyBeanPostProcessor"></bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值