和咱们常据说的另外一个概念IOC(控制反转)其实归根结底实现的功能是相同的,只是一样的功能站在不一样的角度来阐述罢了。咱们须要知道的是,什么叫依赖注入,为何要依赖注入。搞清这两点,我想对Spring的学习在思想上就算是上道了。php
在没用使用Spring的时候——也就是没有依赖注入的时候,java应用程序的类与类之间要实现相互的功能协做是比较费劲的,某个类(A)要实现它的功能若是须要依赖另外一个类(B)的协做的话,就须要在A类中主动建立出B类的对象,才能使用B类的方法完成功能(这里看官就不要去纠结静态方法之类的状况了)。这等因而A类须要负责B类对象整个生命周期的管理。在极度简单的状况下,在一个类中new出另外一个类的对象彷佛并无什么问题,可是复杂的应用程序类与类的协做关系每每是多边的,咱们并不知道一个类功能的实现会依赖多少个另类对象来协做,因此在类中自行建立对象而且管理对象的整个生命周期,会形成代码的高度耦合以及不可想象的复杂度。那么,试想,若是咱们能将对象的生命周期交给第三方组件来管理,当某个类须要另外的对象时第三方组件就直接建立出来交给它,这样,类就能够只专一于本身功能的实现,而不用去管理其余类对象的生命周期,这样类的功能就单纯了不少。java
是的,你必定已经明白了,Spring(容器)就是这个第三方组件。咱们只须要告诉Spring(容器)有哪些对象须要管理就好了,不用去关心Spring框架是如何建立对象的。这样,当某个类A须要类B对象时,若是类B已经声明交给了Sping容器管理,那么在程序运行到类A须要类B时,Spring容器就经过依赖注入的方式,将类B对象注入到类A中协助完成业务功能。经过第三方组件的依赖注入,对象无需再自行的建立和管理类与类之间的依赖关系了。对象的建立依赖注入的方式也有多种,譬如接口注入,构造方法注入,setter方法注入等等。说到这里,你对依赖注入应该有比较直白的认知了。至于为何要依赖注入,上文已经说得很明白了,就是为了减小代码中组件之间的耦合度,咱们仍是先经过简单示例来直观感觉下依赖注入比本身管理对象的好处吧——spring
public class Man implements Human {
private QQCar car;
public Man() {
this.car = new QQCar();
}
@Override
public void xiabibi() {
}
public void driveCar(){
car.drive();
}
}
复制代码
接口Car暂有两个实现:奔驰车和QQ车,在以上Man类和QQCar类高度耦合的代码中,老司机经过构造器只建立了QQ车对象,因此只能开QQ车,那么老司机想开奔驰怎么办呢,你让他从新建立奔驰车的对象吗?这样高度耦合的代码彷佛是毫无办法的,那么,咱们经过注入对象的方式对上述代码作一番改进:数据库
public class Man implements Human {
private Car car;
public Man(Car car) {
this.car = car;
}
@Override
public void xiabibi() {
}
public void driveCar() {
car.drive();
}
}
复制代码
以上代码根据多态特性,经过构造器接口注入的方式屏蔽掉了具体的对象实现,这样,老司机就能想开什么车就开什么车了。这就是依赖注入带来的好处。 express
控制反转显然是一个抽象的概念,咱们举一个鲜明的例子来讲明。在现实生活中,人们要用到同样东西的时候,第一反应就是去找到这件东西,好比想喝新鲜橙汁,在没有饮品店的日子里,最直观的作法就是:买果汁机、买橙子,而后准备开水。值得注意的是:这些都是你本身“主动”创造的过程,也就是说一杯橙汁须要你本身创造。编程
然而到了今时今日,因为饮品店的盛行,当咱们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,经过电话等渠道描述你的须要、地址、联系方式等,下订单等待,过一下子就会有人送来橙汁了。app
请注意你并无“主动”去创造橙汁,橙汁是由饮品店创造的,而不是你,然而也彻底达到了你的要求,甚至比你创造的要好上那么一些。框架
这就是一种控制反转的理念,上述的例子已经很好的说明了问题,咱们再来描述一下控制反转的概念:控制反转是一种经过描述(在 Java 中能够是 XML 或者注解)并经过第三方(Spring)去产生或获取特定对象的方式。ide
主动建立的模式中,责任归于开发者,而在被动的模式下,责任归于 IoC 容器,基于这样的被动形式,咱们就说对象被控制反转了。(也能够说是反转了控制)性能
package pojo;
public class Source {
private String fruit;
private String sugar;
private String size;
}
复制代码
package pojo;
public class JuiceMaker {
// 惟一关联了一个 Source 对象
private Source source = null;
public String makeJuice(){
String juice = "xxx用户点了一杯" + source.getFruit() + source.getSugar() + source.getSize();
return juice;
}
}
复制代码
<?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 name="source" class="pojo.Source">
<property name="fruit" value="橙子"/>
<property name="sugar" value="多糖"/>
<property name="size" value="超大杯"/>
</bean>
<bean name="juickMaker" class="pojo.JuiceMaker">
<property name="source" ref="source" />
</bean>
</beans>
复制代码
package test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.JuiceMaker;
import pojo.Source;
public class TestSpring {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"applicationContext.xml"}
);
Source source = (Source) context.getBean("source");
System.out.println(source.getFruit());
System.out.println(source.getSugar());
System.out.println(source.getSize());
JuiceMaker juiceMaker = (JuiceMaker) context.getBean("juickMaker");
System.out.println(juiceMaker.makeJuice());
}
}
复制代码
总结: IoC 和 DI 实际上是同一个概念的不一样角度描述,DI 相对 IoC 而言,明确描述了“被注入对象依赖 IoC 容器配置依赖对象”
若是说 IoC 是 Spring 的核心,那么面向切面编程就是 Spring 最为重要的功能之一了,在数据库事务中切面编程被普遍使用。
首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,而后把切面功能和核心业务功能 "编织" 在一块儿,这就叫AOP
AOP可以将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减小系统的重复代码,下降模块间的耦合度,并有利于将来的可拓展性和可维护性。
package service;
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
}
复制代码
<bean name="productService" class="service.ProductService" />
复制代码
package aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
复制代码
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean name="productService" class="service.ProductService" />
<bean id="loggerAspect" class="aspect.LoggerAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- where:在哪些地方(包.类.方法)作增长 -->
<aop:pointcut id="loggerCutpoint" expression="execution(* service.ProductService.*(..)) "/>
<!-- what:作什么加强 -->
<aop:aspect id="logAspect" ref="loggerAspect">
<!-- when:在什么时机(方法前/后/先后) -->
<aop:around pointcut-ref="loggerCutpoint" method="log"/>
</aop:aspect>
</aop:config>
</beans>
复制代码