Spring IoC就是控制反转,也被称为依赖注入(Dependency Injection, DI),是面向对象编程中的一种设计理念,用来下降程序代码之间的耦合度。正则表达式
依赖是什么:算法
依赖就是在代码中经过局部变量、方法参数、返回值等创建的对于其余对象的调用关系。spring
1 /** 2 * @content 接口 3 * @author Gawain 4 * @date 2017-8-15下午8:02:37 5 */ 6 public interface DependDemo { 7 /** 8 * 显示信息 9 */ 10 void showInfo(); 11 } 12 13 /** 14 * @content 实现类 15 * @author Gawain 16 * @date 2017-8-15下午8:02:30 17 */ 18 public class DependDemoImpl implements DependDemo { 19 /** 20 * 实现方法 21 */ 22 @Override 23 public void showInfo() { 24 System.out.println("你好"); 25 } 26 } 27 28 /** 29 * @content 测试类 30 * @author Gawain 31 * @date 2017-8-15下午8:02:09 32 */ 33 public class Demo { 34 public static void main(String[] args) { 35 //实例化依赖的对象,此时,Demo类依赖于DependDemoImpl类 36 DependDemo demo = new DependDemoImpl(); 37 //调用方法 38 demo.showInfo(); 39 } 40 }
经过上面的代码能够看出,Demo类和DependDemoImpl类高度耦合,若是需求变化须要替换DependDemo接口的实现类DependDemoImpl的话,那么Demo中的代码也须要进行改动。编程
解决方法(控制反转):设计模式
建立一个对象工厂,将建立实例的工做交给工厂去作,得到对象时不经过new的方式而是经过工厂来得到对象。数据结构
1 /** 2 * @content 对象工厂 3 * @author Gawain 4 * @date 2017-8-15下午8:11:27 5 */ 6 public class Factory { 7 /** 8 * 返回对象实例 9 * @return 10 */ 11 public static DependDemo getDepend() { 12 return new DependDemoImpl(); 13 } 14 } 15 16 /** 17 * @content 测试类 18 * @author Gawain 19 * @date 2017-8-15下午8:02:09 20 */ 21 public class Demo { 22 public static void main(String[] args) { 23 //经过对象工厂得到实例 24 DependDemo demo = Factory.getDepend(); 25 //调用方法 26 demo.showInfo(); 27 } 28 }
经过上面的代码能够看出,Demo类再也不依靠自身的代码去得到所依赖的具体的DependDemo对象,而是将这一工做交给了对象工厂去作,若是DependDemo接口的实现类须要替换的话,只要在工厂类修改代码便可。此时由工厂来控制建立对象而不是Demo自己,这就是控制反转。app
按照上面的方法虽然能够解决问题,可是大量的工厂类会被引入到开发过程当中,大大的增长了开发的工做量。此时咱们就须要用到Spring了。框架
Spring为咱们提供了完整的IoC实现,让咱们得以专一于业务类和DAO类的设计。数据结构和算法
1.下载Spring的jar包并添加到项目中。也可使用MyEclipse来简化这一步骤。右击项目,选择MyEclipse-->Add Spring Capabilities...而后直接点击Finish。ide
2.编写Spring配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 8 <!-- 经过bean元素声明须要Spring建立的实例。该实例的类型经过class属性指定,并经过id属性为该实例指定一个名称,以便于访问 --> 9 <bean id="dependDemo" class="com.jazz.demo.DependDemoImpl"/> 10 </beans>
补充:
1.applicationContext.xml是MyEclipse自动帮你添加的。若是你是本身导的jar包的话,这一文件需本身手动建立。
2.上述代码中的id属性也可使用name属性来完成相同的工做。两者的不一样之处在于id属性只能指定一个名称,而name属性能够指定多个名称,多个名称之间使用空格或者逗号隔开。
3.class属性是类的全限定类名。
3.编写代码经过Spring获取DependDemo实例
1 import org.springframework.context.ApplicationContext; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 4 /** 5 * @content 测试类 6 * @author Gawain 7 * @date 2017-8-15下午8:02:09 8 */ 9 public class Demo { 10 public static void main(String[] args) { 11 //经过ClassPathXmlApplicationContext实例化Spring的上下文 12 ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml"); 13 //经过ApplicationContext的getBean()方法根据id来获取bean的实例 14 DependDemo demo = con.getBean("dependDemo", DependDemoImpl.class); 15 //调用方法 16 demo.showInfo(); 17 } 18 }
补充:
1.在上面的代码中,ApplicationContext是一个接口,负责读取Spring配置文件,管理对象的加载、生成,维护Bean对象与Bean对象之间的依赖关系,负责Bean的生命周期等。
2.ClassPathXmlApplicationContext是ApplicationContext接口的实现类,用于从classpath路径中读取Spring配置文件。classpath路径就是src文件夹。
3.写在配置文件中的Bean会在ClassPathXmlApplicationContext加载Spring配置文件时建立生成。
Spring IoC它就是一个容器,负责管理Bean的建立以及管理Bean与Bean之间的关系等等。
依赖注入是什么?
依赖注入就是将Bean的建立以及为属性赋值的工做交给Spring容器来作,从而避免组件之间以硬编码的方式耦合在一块儿。
上文提到过,Spring IoC不只能够管理对象的加载与生成,还能够管理Bean与Bean之间的依赖关系。除此以外,还能够在建立Bean时为Bean中的属性赋初值。
下面再写一个小例子演示一下依赖注入。
1 /** 2 * @content 书实体类 3 * @author Gawain 4 * @date 2017-8-15下午9:16:43 5 */ 6 public class Book { 7 //书籍名称 8 private String bookName; 9 //重写toString方法 10 @Override 11 public String toString() { 12 return "Book [bookName=" + bookName + "]"; 13 } 14 15 public String getBookName() { 16 return bookName; 17 } 18 19 public void setBookName(String bookName) { 20 this.bookName = bookName; 21 } 22 } 23 24 25 /** 26 * @content 用户实体类 27 * @author Gawain 28 * @date 2017-8-15下午9:15:52 29 */ 30 public class User { 31 //姓名 32 private String name; 33 //年龄 34 private int age; 35 //正在读的书籍 36 private Book book; 37 //重写toString方法 38 @Override 39 public String toString() { 40 return "User [name=" + name + ", age=" + age + ", book=" + book + "]"; 41 } 42 public String getName() { 43 return name; 44 } 45 public void setName(String name) { 46 this.name = name; 47 } 48 public int getAge() { 49 return age; 50 } 51 public void setAge(int age) { 52 this.age = age; 53 } 54 public Book getBook() { 55 return book; 56 } 57 public void setBook(Book book) { 58 this.book = book; 59 } 60 }
1 /** 2 * @content 业务逻辑层接口 3 * @author Gawain 4 * @date 2017-8-15下午9:13:48 5 */ 6 public interface UserService { 7 /** 8 * 显示信息 9 */ 10 void showInfo(); 11 } 12 13 14 /** 15 * @content 业务逻辑层实现类 16 * @author Gawain 17 * @date 2017-8-15下午9:39:25 18 */ 19 public class UserServiceImpl implements UserService { 20 private User user; 21 public User getUser() { 22 return user; 23 } 24 public void setUser(User user) { 25 this.user = user; 26 } 27 //显示用户信息 28 @Override 29 public void showInfo() { 30 System.out.println(user); 31 } 32 }
1 /** 2 * @content user控制层,此处做为测试类 3 * @author Gawain 4 * @date 2017-8-15下午9:31:35 5 */ 6 public class UserController { 7 public static void main(String[] args) { 8 ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml"); 9 UserService userService = con.getBean("userService", UserServiceImpl.class); 10 userService.showInfo(); 11 } 12 }
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 8 <!-- 经过bean元素声明须要Spring建立的实例。该实例的类型经过class属性指定,并经过id属性为该实例指定一个名称,以便于访问 --> 9 <bean id="dependDemo" class="com.jazz.demo.DependDemoImpl"/> 10 <!-- 声明book对象 --> 11 <bean id="book" class="com.jazz.pojo.Book"> 12 <!-- 为属性赋值 --> 13 <property name="bookName" value="Java数据结构和算法" /> 14 </bean> 15 <!-- 声明user对象 --> 16 <bean id="user" class="com.jazz.pojo.User"> 17 <property name="name" value="Gawain" /> 18 <property name="age" value="18" /> 19 <!-- 使用ref引用book对象,添加依赖关系 --> 20 <property name="book" ref="book" /> 21 </bean> 22 <!-- 声明service对象 --> 23 <bean id="userService" class="com.jazz.services.impl.UserServiceImpl"> 24 <property name="user" ref="user"/> 25 </bean> 26 </beans>
补充:
1.为属性赋值的方式有不少种,除了上文的设值注入外,还有构造注入和p命名空间注入。
构造注入语法:
<constructor-arg index="" value="" />
其中value是值,index是指构造方法中的第几个参数,从0开始。
p命名空间注入语法:
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:p="http://www.springframework.org/schema/p" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <bean name="john-classic" class="com.example.Person"> 7 <property name="name" value="John Doe"/> 8 <property name="spouse" ref="jane"/> 9 </bean> 10 <bean name="john-modern" 11 class="com.example.Person" 12 p:name="John Doe" 13 p:spouse-ref="jane"/> 14 <bean name="jane" class="com.example.Person"> 15 <property name="name" value="Jane Doe"/> 16 </bean> 17 </beans>
使用p命名空间注入须要在beans中添加两个url,基本类型的属性使用p:属性名=属性值的方式注入,引用类型的属性使用p:属性名-ref=引用bean的id的方式注入。
2.除了基本数据类型和自定义数据类型以外,Spring还支持不少数据类型,以下图所示。此处就不一一列举了。你们能够去Spring的帮助文档中查看。
依赖注入其实就是将对象之间的依赖关系交给Spring来管理和组装了。不要看它名字说的很“高大上”,其实实现起来很简单。
Spring AOP简介:
Spring AOP就是面向切面编程(Aspect Oriented Programming, AOP),是软件编程思想发展到必定阶段的产物,是面向对象编程(Object Oriented Programming, OOP)的有益补充。AOP通常适用于具备横切逻辑的场合,例如访问控制、事务管理、性能检测等。
横切逻辑是什么:
你们先来看一段代码
1 public class UserController { 2 //声明日志 3 static Logger log = Logger.getLogger(UserController.class); 4 public static void main(String[] args) { 5 //在方法执行前输出日志 6 log.info("显示用户信息"); 7 //使用try-catch来进行对异常的处理 8 try { 9 ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml"); 10 UserService userService = con.getBean("userService", UserServiceImpl.class); 11 userService.showInfo(); 12 } catch (Exception e) { 13 log.error("显示用户信息失败", e); 14 } 15 } 16 }
上面的代码是一段典型的日志输出+异常处理的代码,从上面的代码能够看出,代码中添加了大量的日志和异常处理的代码,而咱们实际的业务代码只有3行。
日志、异常处理、事务控制是一个健壮的业务系统所必须的,可是为了保证系统健壮可用,就须要在众多的业务方法中“反复”编写相似的代码,使得本来就很复杂的业务处理代码变得更加复杂。
在业务系统中,总有一些散落、渗透到系统各处且不得不处理的事情,这些穿插在既定业务中的操做就是所谓的“横切逻辑”,也被称为“切面”。
面向切面编程极大的简化了上面代码中“重复”但又不得不写的代码,可使咱们在不改变原程序的基础上为代码段增长新的功能,对代码段进行加强处理。它的设计思想来源于代理设计模式。
Spring AOP基本概念:
1.切面(Aspect):一个模块化的横切逻辑(或横切关注点),可能会横切多个对象。
2.链接点(Join Point):程序执行中的某个具体的执行点。
3.加强处理(Advice):切面在某个特定链接点上执行的代码逻辑。
4.切入点(Pointcut):对链接点的特征进行描述,可使用正则表达式。加强处理和一个切入点表达式关联,并在与这个切入点匹配的某个链接点上运行。
5.目标对象(Target object):被一个或多个切面加强的对象。
6.AOP代理(AOP proxy):由AOP框架所建立的对象,实现执行加强处理方法等功能。
7.织入(Weaving):将加强处理链接到应用程序中的类型或对象上的过程。
8.加强处理类型:有前置加强、后置加强、环绕加强、异常抛出加强、最终加强等等。这些加强处理实现方式都差很少。
除了上文说的技术以外,spring的帮助文档也给咱们提供了至关全面且详细的说明。