spring三个核心思想详解



Spring核心思想分三大类:控制反转(IOC),依赖注入(DI)和面向切面(AOP)

控制反转

通俗讲,控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。也就是说,正常我们都是新建对象,才可以调用对象。现在不需要了,交给容器来管理,我们只需要通过一些配置来完成把实体类交给容器这么个过程。这样可以减少代码量,简化开发的复杂度和耦合度。

这里,我要解释下几个概念:
1.控制反转只是一个概念,我理解为一种设计模式。
2.控制反转的主要形式有两种:依赖查找和依赖注入

依赖查找:容器提供回调接口和上下文条件给组件。EJB和Apache Avalon 都使用这种方式。这样一来,组件就必须使用容器提供的API来查找资源和协作对象,仅有的控制反转只体现在那些回调方法上(也就是上面所说的 类型1):容器将调用这些回调方法,从而让应用代码获得相关资源。
依赖注入:组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。通过JavaBean属性注射依赖关系的做法称为设值方法注入(Setter Injection);将依赖关系作为构造函数参数传入的做法称为构造器注入(Constructor Injection)。



依赖注入

上面也解释了这个概念,其实现方式有三种:属性注入(setter注入),构造器注入和自动装配。

方式一、属性注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.spring.demo02.entity;  
public class Programmer {  
  
    private String name;  
    private String sex;  
  
    // 在这里定义要依赖的computer属性,加上set方法  
    private Computer computer;  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public String getSex() {  
        return sex;  
    }  
  
    public void setSex(String sex) {  
        this.sex = sex;  
    }  
  
    public Computer getComputer() {  
        return computer;  
    }  
  
    /** 
     * 加上Setter方法 
     * */  
    public void setComputer(Computer computer) {  
        this.computer = computer;  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.spring.demo02.entity;  
public class Computer {

private String brand;
private String color;
private String size;

public void coding() {
System.out.println("Computer is coding!!!");
}

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

public String getColor() {
return color;
}

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

public String getSize() {
return size;
}

public void setSize(String size) {
this.size = size;
}
}

看上面的代码,可以发现:

  • Programmer类里面,有3个属性,name,sex,computer,并且都有对应的getter、setter方法;

  • Computer类里面也有三个属性,分别是品牌、颜色、尺寸,也都有对应的getter、setter方法;

这只是第一步,在类里面声明属性并且实现set方法。

接下来,要写一个spring的xml配置文件,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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-3.0.xsd">  

  <bean id="programmer" class="com.spring.demo2.entity.Programmer">  
    <property name="name" value="小李"></property>
    <property name="sex" value="男"></property>
    <property name="computer" ref="computer"></property>  
  </bean>  

  <bean id="computer" class="com.spring.demo2.entity.Computer">  
    <property name="brand" value="hp"></property>  
    <property name="color" value="黑"></property>  
    <property name="size" value="14"></property>  
  </bean>
</beans>

解读一下这个xml文件:

  1. 声明一个bean,可以理解为实例化了一个对象。那这里实例化了两个对象(programmer和computer),各个属性都已经赋值上去。

  2. id为programmer的bean,其实就是Programmer类;通过给property赋值,Spring就会通过Programmer类的各个属性的set方法,逐一给Programmer的属性赋值。

  3. 在programmer里面,有一个属性是computer的,可以看到它属性值是 ref=”computer”,这就说明computer这个属性是个引用,这里ref后面的值其实就是指向另一个bean的id值,所以这里引用的是id为computer的bean。

以上,就是属性注入了。关键的是在类里面声明属性,写set方法,然后在xml里面配置bean和property的值。

方式二、构造器注入

构造器注入,顾名思义,就是在构造器里面注入依赖对象。那是怎么实现的呢?其实跟属性注入差不多,定义一个有参构造器,然后配置xml文件就行了。看代码:

1
2
3
4
5
6
7
8
9
10
11
package com.spring.demo03.entity;  
import com.spring.demo02.entity.Computer;

public class Programmer {

private Computer computer;

public Programmer(Computer computer){
this.computer = computer;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.spring.demo03.entity;  

public class Computer {

private String brand;
private String color;
private String size;

public Computer(String brand, String color, String size) {
this.brand = brand;
this.color = color;
this.size = size;
}
}

上面两个类都有一个有参的构造器,接下来,在xml里面配置这两个bean,然后再配置构造器的参数值就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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-3.0.xsd">  
      
  <bean id="programmer" class="com.spring.demo3.entity.Programmer">  
    <constructor-arg ref="computer"></constructor-arg>  
  </bean>  

  <!-- 构造器里面没有name字段,只有value,是根据构造器的方法参数顺序来定义的 -->  
  <bean id="computer" class="com.spring.demo3.entity.Computer">  
    <constructor-arg value="联想"></constructor-arg>  
    <constructor-arg value="红色"></constructor-arg>  
    <constructor-arg value="15.6寸"></constructor-arg>  
  </bean>  
    
</beans>

方式三:自动装配

1
2
3
4
5
6
7
8
9
10
11
package com.spring.demo04.entity;  
  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Component;  
  
@Component  
public class Programmer {

    @Autowired  
    Computer computer;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.spring.demo04.entity;  
  
import org.springframework.stereotype.Component;  
  
@Component  
public class Computer {  
    private String brand;  
    private String color;  
    private String size;
 
    public String getBrand() {  
        return brand;  
    }  
  
    public void setBrand(String brand) {  
        this.brand = brand;  
    }  
  
    public String getColor() {  
        return color;  
    }  
  
    public void setColor(String color) {  
        this.color = color;  
    }  
  
    public String getSize() {  
        return size;  
    }  
  
    public void setSize(String size) {  
        this.size = size;  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
<?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:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/context   
    http://www.springframework.org/schema/context/spring-context-3.0.xsd   
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  

    <context:component-scan base-pakage="com.spring.demo04">  
</beans>

关键点:

  1. 在类前面加注解:@Component;
  2. 在需要注入的类里面加注解:@Autowired,这样xml里面的自动扫描就会扫描到这些加了注解的类和属性,在实例化bean的时候,Spring容器会把加了@Component的类实例化;在实际运行时,会给加了@Autowired的属性注入对应的实例。@Autowired方式是通过反射来设置属性值的;

具体参考:https://blog.csdn.net/wenluoxicheng/article/details/73608657

面向切面

面向切面是一个概念,通常用来为许多其他的类提供相同的服务,而且是固定的服务,是独立的。提升了代码的复用性,减少了代码的耦合度,减轻程序员的工作负担,把程序的重心放在了核心的逻辑上。

它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

应用场景有日志记录,性能统计,安全控制,事务处理,异常处理等。