Spring

Spring 中的IOC(控制反转)

以前创建对象都是通过new的形式来创建的,比如在项目中,Controller层需要Service的对象,需要在Controller中new出来使用才行,但是,随着业务的增加,Controller也随之对了起来,相对应的Service也new的越来越多,有时候控制不当,甚至每个方法里面都要new一个,这样会导致代码内存中对于Service的对象就有很多,出现两个缺点:1,Service的对象很多,占内存;2,代码不简洁,到处都是new的Service的对象;
IOC就是针对这俩问题的,相当于Spring提供了一个容器,这个容器专门用来放实例化的对象,比如之前的Service的对象,在这个容器中,要用的时候就去里面取出来就行,不用再自己去new,而且Spring对于这些实例化对象的Bean默认都是单例创建的,多以每个类的对象只能存在一个,不会占内存。
所以IOC,控制反转,就是将我们创建对象的控制权,交给了Spring,由Spring来统一管理。

Spring 中实例化Bean的方式(三种,也可以是4种)

1,构造方法实例化(无参构造),此处就算无参构造方法是private,私有的,也会成功创建Bean,说明能访问到类中的私有构造方法,显而易见Spring底层用的是反射,如果没有无参构造,直接报错,创建Bean失败,异常:Caused by: java.lang.NoSuchMethodException

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

获取Bean

 ApplicationContext ctx = new  ClassPathXmlApplicationContext("applicationContext.xml");
 BookDao bookDao = (BookDao) ctx.getBean("bookDao");

2,静态工程实例化

//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
    	System.out.println("factory setup....");//模拟必要的业务操作
        return new OrderDaoImpl();
    }
}
//通过静态工厂创建对象
OrderDao orderDao = OrderDaoFactory.getOrderDao();

如何交个Spring来管理呢?

<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
  • class:工厂类的类全名
  • factory-mehod:具体工厂类中创建对象的方法名

获取Bean

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");

3,实例工厂
这么一看,似乎和静态实例工厂模式没啥区别,无非就是将方法换成了非静态的而已:

public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

如何交给Spring来管理呢?

<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
  • factory-bean:工厂的实例对象
  • factory-method:工厂对象中的具体创建对象的方法名

获取Bean

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");

4,FactoryBean

  • 创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    //返回所创建类的Class对象
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}
  • 在Spring的配置文件中进行配置
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

获取Bean

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = (UserDao) ctx.getBean("userDao");

这种方式在Spring去整合其他框架的时候会被用到
FactoryBean接口其实会有三个方法,分别是:

T getObject() throws Exception;

Class<?> getObjectType();

default boolean isSingleton() {
		return true;
}

方法一:getObject(),被重写后,在方法中进行对象的创建并返回
方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象
方法三:没有被重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单例,默认true。

Bean的生命周期

1.生命周期
从对象创建到对象销毁的过程
2. bean生命周期

  1. 通过构造器创建bean实例(默认无参数构造)
  2. 为bean的属性设置值和对其他bean引用(调用set方法)
  3. 把bean实例传递给bean前置处理器的方法postProcessBeforeInitialization
  4. 调用bean的初始化方法
  5. 把bean实例传递给bean后置处理器的方法postProcessAfterInitialization
  6. 获取bean实例对象
  7. 当容器关闭时候,调用bean的销毁方法

3.演示bean生命周期
创建Order类

public class Order {
    String name;

    public Order() {
        System.out.println("第一步:调用无参构造方法");
    }
    public void setName(String name) {
        this.name = name;
        System.out.println("第二步:调用set方法");
    }
    public void add(){
        System.out.println("第四步:调用初始化方法");
    }
    public void sub(){
        System.out.println("第七步:调用销毁方法");
    }
}

实现BeanPostProcessor接口

public class MybeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第三步:调用before方法");
        return null;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第五步:调用After方法");
        return null;
    }
}

创建配置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="order" class="com.github.entity.Order" init-method="add" destroy-method="sub">
        <property name="name" value="订单"></property>
    </bean>
    <bean id="mybeanPost" class="com.github.entity.MybeanPost"></bean>
</beans>

编写测试类

public class OrderTest {
    @Test
    public void test(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");
        Order order = context.getBean("order",Order.class);
        System.out.println("第六步:获取实例对象");
        context.close();
    }
}

image

Spring中的DI(依赖注入)

在实际开发过程中,可能会存在这种情况,比如一个Controller中,需要某些Service的对象,我们需要将Service的对象注入到Controller中,这就叫做依赖注入,简单来讲就是绑定Spring IOC容器中的各个Bean的关系,建立对象与对象之间的绑定关系,这就叫做依赖注入。

Spring中的AOP(面向切面编程)