在学习Spring之前,需要理解两个概念,IoC和AOP。刚刚看到的时候,我是一头雾水,慢慢的在使用过程之中我才理解其中的含义。
1. IoC
IoC,即Inversion of Control,控制反转。什么是控制反转呢?
摘自百度百科
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
反复阅读这段话,其实能大概读懂IoC的含义了:
- “控制反转”是一种设计思想;
- 依赖的对象由“外界”传入;
- IoC的目的是降低耦合度。
其中,1和3很好理解,重点在于第2点。
当一个对象依赖另一个对象的时候,往往我们需要通过new来获取。举个例子,我们现在有两个类,分别是Person和Car,分别代表人和车:
public class Person {
private Car car;
public void drive(){
car = new Car();
car.run();
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
public class Car {
private String brand;
public void run() {
String carName = brand == null ? "car" : brand;
System.out.println(carName + " is running");
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
Person有一个Car类型的成员变量car,当人要开车的时候,就会调用drive
方法,drive
又会调用Car的run
方法,汽车就跑起来了。这个过程在main里面是这样表示:
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.drive();
}
}
现在的依赖关系是这样的:
在这里,当Person需要调用car.run()
的时候,是通过car = new Car();
来创建实例。因为person是依赖car的,而car又是在person之中创建的;换句话说,是person控制了car的创建。而控制反转即是让person丧失创建car(依赖对象)的主动权,反过来让外界传入。这个“外界”被称之为IoC容器。
1.1 Spring中的IoC
在Spring中,对象的创建是通过Spring IoC容器来进行的,通过配置xml的方式来进行。
在IDEA中新建Spring项目,命名为SpringNote,目录结构如下:
在src下新建文件applicationContext.xml,内容如下:
这里定义了两个bean,分别是car和person。然后,将car的brand成员赋值为“Benz”,再将这个car传入给person。现在,Spring会帮我们控制car的创建,所以Person类中就不用自己new了:
public class Person {
private Car car;
public void drive() {
car.run();
}
// getter and setter
}
Main中,通过ApplicationContext来获取对象:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = context.getBean("person", Person.class);
person.drive();
}
}
运行一下,发现运行成功。在这个过程中,我们的代码中既没有创建任何Person或者Car,也没有给他们的成员赋值,就能让奔驰车开始奔驰,这全都归功于Spring的IoC容器。
这样一来,相当于有了一个中央控制器,隔绝了Person和Car,二者之间通过中间的IoC容器建立联系。这样降低了类之间的耦合度(实际情况中更多通过接口来实现)。
2. AOP
AOP,即Aspect-Oriented Programming,面向切面编程。
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
也就是说,AOP的重点在于,把与业务逻辑无关,但又在业务中通用的模块(如日志)提取出来,增加了代码的复用,同时又降低了模块间的耦合。
以1中的例子为例。现在我们要在汽车启动前和停止后分别输出日志。新建日志切面类LogAspect:
import org.aspectj.lang.ProceedingJoinPoint;
public class LogAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开始启动汽车");
Object o = joinPoint.proceed();
System.out.println("结束行程,停车熄火");
return o;
}
}
这里需要依赖aspectj的jar包,如果没有则下载即可。
然后,在xml中配置aop:
再运行Main,结果就如下所示了: