spring的注入和直接new一个对象有啥不同?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring的注入和直接new一个对象有啥不同?相关的知识,希望对你有一定的参考价值。

一、意思不同

spring依赖注入,是指对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。

例如:

A对象需要引用B对象的话,可以在A的构造函数里面将B传递进去,或者调用A的某个set方法。

通俗一点就是spring已经new好了, 要用直接取拿。

二、顺序

new一个对象的时候,初始化顺序是:

父类静态块,子类静态块,父类属性(先系统默认值,后直接你赋予的值) ,父类构造器,子类属性,子类构造器。

三、要求

Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理,依赖注入通常有三种:

1、 set设值注入 

2、构造方法注入 

3、spring注解注入 

参考技术A spring注入方便管理,依赖注入或者说是控制反转,说白了就是使用了配置文件,这种思想的唯一好处就是增加了模块的重用性灵活性。

一般配置文件里存的都是数据,键值之类的。Spring的配置文件把要引用类和要给类传的参数都放到配置文件里,这样比以前写死在程序里new一个对象更灵活,因此更具重用性。
参考技术B spring实现了对象池,一些对象创建和使用完毕之后不会被销毁,放进对象池(某种集合)以备下次使用,下次再需要这个对象,不new,直接从池里出去来用。节省时间,节省cpu 参考技术C 依赖注入,是指对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。
注入有三种方式:构造函数传递,set方法设置,注解

举个例子:A对象需要引用B对象的话,可以在A的构造函数里面将B传递进去,或者调用A的某个set方法,或者用注解的方式(jdk1.5以上)
说到这里,你应该明白从功能角度来讲,依赖注入和new一个对象是没有可比性的

如何在静态方法或非Spring Bean中注入Spring Bean

       在项目中有时需要根据需要在自己new一个对象,或者在某些util方法或属性中获取Spring Bean对象,从而完成某些工作,但是由于自己new的对象和util方法并不是受Spring所管理的,如果直接在所依赖的属性上使用@Autowired就会报无法注入的错误,或者是没报错,但是使用的时候会报空指针异常。总而言之由于其是不受IoC容器所管理的,因而无法注入。

        Spring提供了两个接口:BeanFactoryAware和ApplicationContextAware,这两个接口都继承自Aware接口。如下是这两个接口的声明:

public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

       在Spring官方文档中描述,在初始化Spring bean时,如果检测到某个bean实现了这两个接口中的一个,那么就会自动调用该bean所实现的接口方法。这里可以看到,这两个方法都是将IoC容器管理bean的工厂对象传递给当前bean,也就是说如果我们在当前bean中将工厂对象保存到某个静态属性中,那么我们就能够通过工厂对象获取到我们需要的bean。如下是使用ApplicationContextAware实现的一个SpringBeanUtil:

public class SpringBeanUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) 
      throws BeansException {
        SpringBeanUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return (T) applicationContext.getBean(clazz);
    }

    public static Object getBean(String name) throws BeansException {

        return applicationContext.getBean(name);
    }
}

       这里还需要在配置文件中指定创建当前类的一个实例:

<bean id="springBeanFactory" class="com.business.util.SpringBeanUtil"/>

       可以看到,我们再SpringBeanUtil中声明了一个ApplicationContext类型的静态属性,并且在setApplicationContext()方法中将获取到的ApplicationContext赋值给了该静态属性,这样我们就可以在另外两个声明的静态方法中通过ApplicationContext获取IoC容器所管理的bean了。如下是一个测试示例:

public class ClassRoom {
  public void describeStudent() {
    Student student = SpringBeanUtil.getBean(Student.class);
    System.out.println(student);
  }

  public static void describeClassRoomCapacity() {
    Student student = SpringBeanUtil.getBean(Student.class);
    System.out.println("Is it not empty? " + (null != student));
  }
}
public class Student {
  @Override
  public String toString() {
    return "I am a student.";
  }
}
<bean id="springBeanFactory" class="com.util.SpringBeanUtil"/>
<bean id="student" class="com.domain.Student"/>

如下是驱动类:

public class BeanApp {
  public static void main(String[] args) {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("com/resources/application.xml");
    ClassRoom.describeClassRoomCapacity();
    ClassRoom classRoom = new ClassRoom();
    classRoom.describeStudent();
  }
}

       在驱动类中,我们首先使用ClassPathXmlApplicationContext加载配置文件中的bean。可以看到,我们创建了一个SpringBeanUtil和一个Student的bean。我们首先在静态方法中获取了Student实例,并将其打印出来了,我们也在new出来的ClassRoom实例中通过SpringBeanUtil获取了Student实例,并且对其进行了输出。如下是输出结果:

Is it not empty? true
I am a student.

        可以看到,无论是在静态方法中,还是在手动new的实例中,我们都成功获取了IoC容器所管理的bean。如果我们想在静态属性中获取SpringBean,其实也非常简单,直接对属性赋值即可,如下所示:

private static Student student = SpringBeanUtil.getBean(Student.class);

以上是关于spring的注入和直接new一个对象有啥不同?的主要内容,如果未能解决你的问题,请参考以下文章

有啥好书讲解spring框架的原理和用法的麽

spring框架有啥用?

Spring依赖注入就是这么简单

Spring IOC-介绍和使用

自己new的对象怎么注入spring管理的对象

java中的依赖注入和引用对象有啥区别