Spring核心概念

Posted

tags:

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

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

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

依赖注入:设值注入和构造注入

1.设值注入

 1 package cn.springdemo;
 2 
 3 /**
 4  * 第一个Spring,输出"Hello,Spring!"。
 5  * 
 6  * @author 北大青鸟
 7  */
 8 public class HelloSpring {
 9     // 定义who属性,该属性的值将通过Spring框架进行设置
10     private String who = null;
11 
12     /**
13      * 定义打印方法,输出一句完整的问候。
14      */
15     public void print() {
16         System.out.println("Hello," + this.getWho() + "!");
17     }
18 
19     public String getWho() {
20         return who;
21     }
22     public void setWho(String who) {
23         this.who = who;
24     }
25 
26 }     
 1 <?xml version="1.0" encoding="UTF-8"?>
 2  <beans xmlns="http://www.springframework.org/schema/beans"
 3      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4       xsi:schemaLocation="http://www.springframework.org/schema/beans
 5      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
 6      <!-- 通过bean元素声明需要Spring创建的实例。该实例的类型通过class属性指定,
 7      并通过id属性为该实例指定一个名称,以便在程序中使用 -->
 8      <bean id="helloSpring" class="cn.springdemo.HelloSpring">
 9          <!-- property元素用来为实例的属性赋值,此处实际是调用setWho()方法实现赋值操作 -->
10         <property name="who">    
11          <!-- 此处将字符串"Spring"赋值给who属性 -->    
12            <value>Spring</value>
13          </property>
14      </bean>
15  </beans>
 1 package test;
 2 
 3 import org.junit.Test;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.support.ClassPathXmlApplicationContext;
 6 
 7 import cn.springdemo.HelloSpring;
 8 
 9 public class HelloSpringTest {
10 
11     @Test
12     public void helloSpring() {
13         // 通过ClassPathXmlApplicationContext实例化Spring的上下文
14         ApplicationContext context = new ClassPathXmlApplicationContext(
15                 "applicationContext.xml");
16         // 通过ApplicationContext的getBean()方法,根据id来获取bean的实例
17         HelloSpring helloSpring = (HelloSpring) context.getBean("helloSpring");
18         // 执行print()方法
19         helloSpring.print();
20     }
21 
22 }

除了ClassPathXmlApplicationContext、ApplicationContext接口还有其它实现类,例如FileSystemXmlApplicationContext也可以用于加载Spring配置文件。

ClassPathXmlApplicationContext:读取的默认路径为src下一级目录。

FileSystemXmlApplicationContext:读取的默认路径为项目名下一级目录,与src同级。

2.构造注入

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://www.springframework.org/schema/beans
 5     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd ">
 6     <!-- 定义UserDaoImpl对象,并指定id为userDao -->
 7     <bean id="userDao" class="dao.impl.UserDaoImpl" />
 8     <!-- 定义UserServiceImpl对象,并指定id为userService -->
 9     <bean id="userService" class="service.impl.UserServiceImpl">
10         <!-- 通过定义的单参构造为userService的dao属性赋 值 -->
11         <constructor-arg>
12             <!-- 引用id为userDao的对象为userService的dao属性赋值 -->
13             <ref bean="userDao" />
14         </constructor-arg>
15     </bean>
16 </beans>

一个<constructor-arg>元素表示构造方法的一个参数,且使用时不区分顺序。当构造方法的参数出现混淆、无法区分时,可以通过<constructor-arg>元素的index属性指定该参数的位置索引,位置从0开始。<constructor-arg>还提供了type属性指定参数的类型。

=======================================================================================================================================================================================================

AOP(Aspect Oriented Programming,AOP)面向切面编程,简单来说就是在不改变原程序的基础上为代码段增加新的功能,对代码段进行增强处理。

  切面(Aspect):一个模块化的横切逻辑(或称横切关注点),可能会横切多个对象。

  连接点(Join Point):程序执行中的某个具体的执行点。

  增强处理(Advice):切面在某个特定链接点上执行的代码逻辑。

  切入点(Pointcut):对连接点的特征进行描述,可以使用正则表达式。增强处理和一个切入点表达式相关联,并在与这个切入点匹配的某个连接点上运行。

  目标处理(Target Object):被一个或多个切面增强的对象。

  AOP代理(AOP proxy):由AOP框架所创建的对象,实现执行增强处理方法等功能。

  织入(Weaving):将增强处理连接到应用程序中的类型或对象上的过程。

  增强处理类型:在原对象的方法之前插入的增强为前置增强,该方法正常执行完以后插入的增强处理为后置增强,此外还有环绕增强、异常抛出增强、最终增强等类型。

前置增强和后置增强

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:aop="http://www.springframework.org/schema/aop"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 7     http://www.springframework.org/schema/aop
 8     http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
 9     <bean id="dao" class="dao.impl.UserDaoImpl"></bean>
10     <bean id="service" class="service.impl.UserServiceImpl">
11         <property name="dao" ref="dao"></property>
12     </bean>
13     <!-- 声明增强方法所在的Bean -->
14     <bean id="theLogger" class="aop.UserServiceLogger"></bean>
15     <!-- 配置切面 -->
16     <aop:config>
17         <!-- 定义切入点 -->
18         <aop:pointcut id="pointcut"
19             expression="execution(public void addNewUser(entity.User))" />
20         <!-- 引用包含增强方法的Bean -->
21         <aop:aspect ref="theLogger">
22             <!-- 将before()方法定义为前置增强并引用pointcut切入点 -->
23             <aop:before method="before" pointcut-ref="pointcut"></aop:before>
24             <!-- 将afterReturning()方法定义为后置增强并引用pointcut切入点 -->
25             <!-- 通过returning属性指定为名为result的参数注入返回值 -->
26             <aop:after-returning method="afterReturning"
27                 pointcut-ref="pointcut" returning="result" />
28         </aop:aspect>
29     </aop:config>
30 </beans>
 1 package aop;
 2 
 3 import java.util.Arrays;
 4 import org.apache.log4j.Logger;
 5 import org.aspectj.lang.JoinPoint;
 6 
 7 public class UserServiceLogger {
 8     private static final Logger log = Logger.getLogger(UserServiceLogger.class);
 9 
10     public void before(JoinPoint jp) {
11         log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
12                 + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
13     }
14     
15     public void afterReturning(JoinPoint jp, Object result) {
16         log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
17                 + " 方法。方法返回值:" + result);
18     }
19 
20 }

为了能够在增强方法中获取当前连接点的信息,可以在增强方法中声明一个JoinPoint类型的参数,Spring会自动注入该实例。通过该实例的getTarget()方法可以得到被代理的目标对象,getSignature()方法返回被代理的目标方法,getArgs()方法返回传递给目标方法的参数数组。对于后置增强的方法,还可以定义一个参数用于接收目标方法的返回值。

异常抛出增强


public void afterThrowing(JoinPoint jp, RuntimeException e) {
        log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
    }

 


1
<bean id="dao" class="dao.impl.UserDaoImpl"></bean> 2 <bean id="service" class="service.impl.UserServiceImpl"> 3 <property name="dao" ref="dao"></property> 4 </bean> 5 <!-- 声明增强方法所在的Bean --> 6 <bean id="theLogger" class="aop.ErrorLogger"></bean> 7 <!-- 配置切面 --> 8 <aop:config> 9 <!-- 定义切入点 --> 10 <aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" /> 11 <!-- 引用包含增强方法的Bean --> 12 <aop:aspect ref="theLogger"> 13 <!-- 将afterThrowing()方法定义为异常抛出增强并引用pointcut切入点 --> 14 <!-- 通过throwing属性指定为名为e的参数注入异常实例 --> 15 <aop:after-throwing method="afterThrowing" 16 pointcut-ref="pointcut" throwing="e" /> 17 </aop:aspect> 18 </aop:config>

环绕增强


public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {
        log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
                + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
        try {
            Object result = jp.proceed();//执行目标方法并获得其返回值
            log.info("调用 " + jp.getTarget() + " 的 "
                    + jp.getSignature().getName() + " 方法。方法返回值:" + result);
            return result;
        } catch (Throwable e) {
            log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
            throw e;
        } finally {
            log.info(jp.getSignature().getName() + " 方法结束执行。");
        }

 


1
<bean id="dao" class="dao.impl.UserDaoImpl"></bean> 2 <bean id="service" class="service.impl.UserServiceImpl"> 3 <property name="dao" ref="dao"></property> 4 </bean> 5 <!-- 声明增强方法所在的Bean --> 6 <bean id="theLogger" class="aop.AroundLogger"></bean> 7 <!-- 配置切面 --> 8 <aop:config> 9 <!-- 定义切入点 --> 10 <aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" /> 11 <!-- 引用包含增强方法的Bean --> 12 <aop:aspect ref="theLogger"> 13 <!-- 将aroundLogger()方法定义为环绕增强并引用pointcut切入点 --> 14 <aop:around method="aroundLogger" pointcut-ref="pointcut"/> 15 </aop:aspect> 16 </aop:config>
ProceedingJoinPoint是JoinPoint的子接口,其不但封装目标方法及其入参数组,还封装了被代理的目标对象,通过它的proceed()方法可以调用真正的目标方法,从而达到对连接点的完全控制。
环绕增强在目标的前后都可以织入增强处理。环绕增强是功能最强大的增强处理,Spring将目标方法的控制权全部交给了它。在环绕增强处理中,可以获取或修改目标方法的参数、返回值,可以对它进行异常处理,甚至可以决定目标方法是否被执行。

最终增强


public void afterLogger(JoinPoint jp) {
        log.info(jp.getSignature().getName() + " 方法结束执行。");
    }
1 <bean id="dao" class="dao.impl.UserDaoImpl"></bean>
 2     <bean id="service" class="service.impl.UserServiceImpl">
 3         <property name="dao" ref="dao"></property>
 4     </bean>
 5     <!-- 声明增强方法所在的Bean -->
 6     <bean id="theLogger" class="aop.AfterLogger"></bean>
 7     <!-- 配置切面 -->
 8     <aop:config>
 9         <!-- 定义切入点 -->
10         <aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" />
11         <!-- 引用包含增强方法的Bean -->
12         <aop:aspect ref="theLogger">
13             <!-- 将afterLogger()方法定义为最终增强并引用pointcut切入点 -->
14             <aop:after method="afterLogger" pointcut-ref="pointcut"/>
15         </aop:aspect>
16     </aop:config>

最终增强的特点是无论方法抛出异常还是正常退出,该增强都会得到执行,类似于异常处理机制中的finally块的作用,一般用于释放资源。














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

第一章 spring核心概念

spring技术核心概念纪要

Spring核心概念

Spring核心概念

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

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