Spring核心概念

Posted 南橘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring核心概念相关的知识,希望对你有一定的参考价值。

 Spring IoC

  Spring IoC就是控制反转,也被称为依赖注入(Dependency Injection, DI),是面向对象编程中的一种设计理念,用来降低程序代码之间的耦合度。

  依赖是什么:

      依赖就是在代码中通过局部变量、方法参数、返回值等建立的对于其他对象的调用关系。

 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本身,这就是控制反转。

      按照上面的方法虽然可以解决问题,但是大量的工厂类会被引入到开发过程中,大大的增加了开发的工作量。此时我们就需要用到Spring了。

      Spring为我们提供了完整的IoC实现,让我们得以专注于业务类和DAO类的设计。

开发Spring项目

  1.下载Spring的jar包并添加到项目中。也可以使用MyEclipse来简化这一步骤。右击项目,选择MyEclipse-->Add Spring Capabilities...然后直接点击Finish。

      

  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>
applicationContext.xml配置文件

        补充:

          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 }
通过SpringIoC容器获取对象实例

       补充:

           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>
applicationContext.xml配置文件

       补充:

          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命名空间注入语法

 

 

                  使用p命名空间注入需要在beans中添加两个url,基本类型的属性使用p:属性名=属性值的方式注入,引用类型的属性使用p:属性名-ref=引用bean的id的方式注入。

          2.除了基本数据类型和自定义数据类型之外,Spring还支持很多数据类型,如下图所示。此处就不一一列举了。大家可以去Spring的帮助文档中查看。

              

              

小结:

  依赖注入其实就是将对象之间的依赖关系交给Spring来管理和组装了。不要看它名字说的很“高大上”,其实实现起来很简单。


 Spring AOP

   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的帮助文档也给我们提供了相当全面且详细的说明。

 

以上是关于Spring核心概念的主要内容,如果未能解决你的问题,请参考以下文章

第一章 spring核心概念

spring技术核心概念纪要

Spring核心概念

Spring核心概念

Spring使用 --- 基本概念:AOP,面向方面编程

片段和活动之间的核心区别是啥?哪些代码可以写成片段?