Spring核心

认识Spring

1.1传统的java EE 开发:

企业级应用是指为商业组织、大型企业创建并部署的解决方案及应用。这些大型企业级应用的结构复杂,涉及的外部资源众多,事务密集、数据规模大、用户数量多,有较强的安全性考虑和较高的性能要求。作为企业级应用,不但要有强大的功能,还要能够满足未来业务需求的发展变化,抑郁扩展和维护。
而传统的java EE在解决企业级应用问题时的“超重量”级架构体系,使他的开发效率、开发难度和实际的性能有很大的不对等。

1.2 Spring整体架构

Spring的优点:
1、是一个轻量级框架。
2、简化了java企业级开发。
3、提供强大、稳定功能的同时并没有带来额外的负担。

Spring的两个主要目标:
一、让现有技术更易于使用;
二、养成良好的编程习惯(或者称最佳实现);

Spring坚持的原则:
不重新发明轮子。已经有较好解决方案的领域,Spring绝不做重复性的实现。

Spring的体系结构
Spring框架由大约20个功能模块组成。这些模块被分成六个部分,分别是 Core Container(核心容器)、
Data Access/Integration(数据访问和集成)、Web、AOP(Aspect Oriented Programming)、Instrumentation()、Test如下图所示:
在这里插入图片描述
Spring Core 是框架的最基础部分,提供了IOC特性。Spring context为企业级开发提供了遍历的集成工具。Spring AOP是基于Spring Core 的符合规范的面向切面编程的实现。Spring JDBC提供了JDBC的抽象层,简化了JDBC的编码…

2.Spring IoC的简单运用

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

2、相对于‘’控制反转”,"依赖注入"的说法也许更容易理解一些,即由容器(如Spring)负责把组件所"依赖”的具体对象“注入”赋值给组件,从而避免组件之间以硬编码的方式耦合在一起。

3、依赖一般是指通过局部变量、方法参数、返回值等建立的对于其他对象的调用关系。几乎所有的应用都有两个或更多的类通过合作来实现完成的功能。类与类之间的依赖关系增加了程序开发的复杂程度,我们在开发一个类的时候,还要考虑对正在使用该类的其他类的影响。

在这里插入图片描述
在这里插入图片描述
如上述代码所示:UserServiceImpl类中有对于UserDaoImpl类的依赖,UserServiceImpl和UserDaoimpl高度耦合,如果因为需求变化需要替换UserDao的实现类,将导致UserServiceImpl中的代码随之发生修改。如此程序将不具备优良的课扩展性和课维护性。在上述示例中我们已经通过注解的方式降低了耦合度。UserServiceImpl不在依靠自身的代码去new 一个UserDao对象,而是把这一工作交由Spring来管理,从而避免了和具体的UserDao实现类之间的耦合。由此可见,在如何获取去所依赖的对象上,“控制权”发生了“反转”,即从UserServiceImpl转移到了Spring,这就是“控制反转”。
而Spring提供了完整的IoC实现,让我们专注于业务类和DAO类的设计。

2.2 Spring实现输出
需求:编写HelloSpring类输出“Hello,Spring!”。
实现思路:
1、导入Spring相关的jar包;
2、编写配置文件;
3、编写代码通过Spring获取HelloSpring实例。

创建项目的步骤省略;
在Project Structure中设置包的属性:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后是整体的目录结构
在这里插入图片描述
在这里插入图片描述
可以看一下引入的jar包
在这里插入图片描述
引入jar包后,开始创建Spring的配置文件:
先创建一个Sring的配置文件,取名为Spring_config.xml
在这里插入图片描述
接着编写SpringHello类:如下图
在这里插入图片描述
接下来编写Spring配置文件

<?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元素声明需要Spring创建的实例。该实例的类型通过Class属性指定,并通过id属性为该实例指定一个名称,以便于访问-->
    <bean id="helloSpring" class="HelloSpring">
    <!--property 元素用来为元素属性赋值,此处实际是调用setWho()方法实现赋值操作
    通过name属性指定属性名称,通过value属性赋值-->
    <property name="who" value="Hello,Spring"/>
    </bean>
</beans>

           在Sprin配置文件中,使用<bean>元素来定义Bean(也可称为组件)的实例。<bean>元素有两个常用属性:一个是id,用来定义该Bean实例的名称;另一个是class,表示定义的Bean实例的类型。

经验:
       1.使用`元素定义一个组件时,通常需要使用id属性为其指定一个用来访问的唯一名称。如果想为Bean指定更多的别名,可以通过name属性来指定,名称之间用逗号、分号或者空格进行分隔。

       2.在本例中,Spring 为Bean的属性赋值是通过调用属性的setter方法实现的,这种做法称为“设值注入”,而非直接为属性赋值。若属性名为who,setter方法名为setSomebody(),Spring 配置文件中应写成name="Somebody:而非name=“who”.所以在为属性和setter访问器命名的时候,一定要遵循jvavaBeand的命名规范.

接下来编写测试类测试一下:

public class TestHelloSpring {
    public void spring(){
    //通过ApplicationContext来实例化Spring_config.xml的上下文(我的理解是用来读取Spring的配置文件)
      ApplicationContext context = new ClassPathXmlApplicationContext("Spring_config.xml");
      //通过ApplicationContext对象的getBean()方法,根据bean的id来获取Beand的实例
      HelloSpring helloSpring = (HelloSpring) context.getBean("helloSpring");
      //执行print()方法
      helloSpring.Print();
    }
}

执行会有结果输出:

在这里插入图片描述

在上述代码中ApplicationContext是一个接口,负责读取Spring配置文件,管理对象的加载、生成、维护Bean对象之间的依赖关系,负责Bean的生命周期等。ClassPathXmlApplicationContext是ApplicationContext接口的实现类,用于从classpath路径中读取Spring配置文件。

扩展:
         1.除了ClassPathXmlApplicationContext,ApplicationContext接口还有其他实现类。如:FileSystemXmlApplicaitonContext也可以用于加载Spring配置文件。
         2、除了ApplicationContext及其实现类,还可以通过BeanFactory接口及其实现类对Bean组件实施管理。事实上,ApplicationContext就是建立在BeanfFactory的基础之上。Beanfacotry接口是SpringIoC容器的核心,负责管理组件和他们之间的依赖关系,应用程序通过BeanFactory接口与Spring IoC容器交互。ApplicationContext是BeanFactory的子接口,可以对企业级开发提供更全面的支持。

3 深入理解IoC/DI

       Spring管理Bean,是将Bean于Bean之间的依赖关系放在配置文件里组织,而不是写在代码里。通过配置文件的指定,Spring能够精确的为每个Bean注入属性。
       每个Bean的id属性时该Bean的唯一标识。程序通过id属性访问Bean,Bean于Bean的依赖关系也通过id属性来完成。
       通过Spring的强大组装能力,我们在开发每个程序组件的时候,只需要明确关联组件的接口定义,二不需要关心具体实现,这就是所谓的“面向接口编程”。

4 SpringAop的简单应用

4.1认识 AOP

       面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Programming,OOP)的有益补充。AOP一般是用于具有横切逻辑的场合,如访问控制、事务管理、性能监测等。
       什么是横切逻辑?所谓横切逻辑就是散落、渗透到系统各处且不得不处理的事情,这些穿插在既定业务中的操作就是所谓的“横切逻辑”,也成为切面。
       所谓的面向切面编程,简单的来说就是在不改变原有程序的基础上为代码段增加新的功能,对其进行增强处理。其设计的思想源于大力设计模式,
在这里插入图片描述
            上图为通过代理对象调用方法

    在代理模式中可以为对象设置一个代理对象,代理对象为func()提供了一个代理方法,当通过大力对象的fun()方法调用原对象的fun()方法时,就可以在代理方法中添加新的功能,这就是所谓的增强处理。增强的功能既可以插入到原对象方法fun()的前面,也可以插入到其后面,如上图。

    下面了解一下AOP的基本概念:
1、切面(Aspect):一个模块化的横切逻辑(或称横切关注点),可能会横切多个对象。
2、连接点(Join Point):程序执行中的某个具体的执行点。上图中的fun()方法就是一个连接点.
3、增强处理(Advice):切面在某个特定连接点上执行的代码逻辑;
4、切入点(Pointcut):对连接点的特征进行描述(对于满足条件的方法进行增强处理),增强处理和一个切入点表达式相关联,并在于这个切入点匹配的某个连接点上运行。
5、目标对象(Target Object):被一个或多个切面增强的对象。
6、AOP代理(AOP proxy):由AOP框架所创建的对象,实现执行增强处理方法等功能。
7、织入(Weaving):将增强处理连接到应用程序中的类型或对象上的过程。
8、增强处理类型:前置增强(在原对象方法前插入的增强处理为前置增强),后置增强(在该方法正常执行完以后插入的增强处理为后置增强)、异常抛出增强(在方法发生异常时插入的增强处理为异常抛出增强)、最终增强(不管方法执行是否发生异常都会执行的增强处理)、环绕增强(在目标方法的前后都可以插入增强处理)。

    补充:切面可以理解为有增强处理和切入点组成,既包含了横切逻辑的定义,也包含了连接点的定义。面向切面编程主要关系两个问题,即在什么位置执行什么功能。Spring AOP 是负责实施切面的框架,即由Spring AOP完成织入工作。

4.2 Spring AOP 初体验

  需求:使用Spring AOP来实现日志输出。
 实现思路:
1、在项目中添加Spring AOP 相关的jar文件。
2、编写前置增强和后置增强实现日志功能。
3、编写Spring配置文件,对业务方法进行增强处理。
4、编写代码,获取带有增强处理的业务对象。

引入jar包:

 <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.0.0.RELEASE</version>
    </dependency>

在这里插入图片描述
编写log4j的properties文件,

### 设置###
log4j.rootLogger = debug,stdout,D

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

接下来,编写业务类:

package cn.kgc.service;

import cn.kgc.dao.UserDao;
/**
 * Desc: 用户业务类,实现对User业务的管理
 * createBy  author
 * Date: 2019/7/5 0005 22:22
 */
public class UserService {
    //声明接口类型的引用和具体实现类解耦
    private UserDao dao;

    //调用dao的方法保存用户信息
    public void addUser(String name){
        dao.addUser(name);
    }
    public UserDao getDao() {
        return dao;
    }
    public void setDao(UserDao dao) {
        this.dao = dao;
    }
}

可以看出在上述方法中并没有日志输出功能,接下来就以AOP的方式为该方法添加日志功能。编写增强类:

package cn.kgc.util;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import java.util.Arrays;

/**
 * Desc: 定义包含增强方法的javaBean
 * createBy:
 * Date: 2019/7/5 0005 22:26
 */
public class UserServiceLogger {
    //将Logger对象设为私有属性
    private static final Logger logger = Logger.getLogger(UserServiceLogger.class);
    //定义前置增强方法,将该方法添加到目标方法执行之前执行
    public void before(JoinPoint jp){
        logger.info("调用:"+jp.getTarget()+"类的:"+jp.getSignature().getName()+"方法。方法入参是:"+ Arrays.toString(jp.getArgs()));
    }
    //定义后置增强方法,将该方法添加到目标方法执行之后执行
    public void afterReturning(JoinPoint jp,Object result){
        logger.info("调用:"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值:"+result);
    }

}

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

  接下来在Spring的配置文件中对相关组件进行声明,并将在切入点插入增强处理,这个过程的专业名称是“织入”。

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--引入包含增强方法的javaBean-->
    <bean id="userServiceLogger" class="cn.kgc.util.UserServiceLogger"/>
    <!--配置切面-->
    <aop:config>
        <!--定义一个切入点表达式 id为此切点的命名  expression用来配置切点 execution用于配置需要切入增强处理的方法特征-->
        <aop:pointcut id="pointcut" expression="execution(* cn.kgc.service.*.*(..))"/>
        <!--织入-在切入点处插入增强处理 通过ref属性为该切面添加userServiceLogger的组件-->
        <aop:aspect ref="userServiceLogger">
            <!--将before()方法定义为前置增强方并引用pointcut切入点-->
            <aop:before method="before" pointcut-ref="pointcut"/>
            <!--将aftereReturning()方法定义为前置增强方并引用pointcut切入点 通过returning属性指定名为result的参数注入返回值-->
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
        </aop:aspect>
    </aop:config>

在这里插入图片描述
   在<beans>中添加aop的名称空间,以导入与AOP相关的标签。与AOP相关的配置都放在<aop:config>标签中,入配置一切入点的标签<aop:pointcut>.<aop:pointcut>的expression属性可以配置切入点表达式,
execution是切入点指示符,括号中是一个切入点表达式,用于配置需要切入增强处理的方法的特征。切入点表达式支持模糊匹配,下面是几种常用的模糊匹配。
下面给出一些通用切入点表达式的例子。

任意公共方法的执行:

execution(public * *(…))
任何一个名字以“set”开始的方法的执行:

execution(* set*(…))
AccountService接口定义的任意方法的执行:

execution(* com.xyz.service.AccountService.*(…))
在service包中定义的任意方法的执行:

execution(* com.xyz.service..(…))
在service包或其子包中定义的任意方法的执行:

execution(* com.xyz.service….(…))
在service包中的任意连接点(在Spring AOP中只是方法执行):

within(com.xyz.service.*)
在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):

within(com.xyz.service…*)

<aop:config>中标签的作用:
<aop:aspect>:引用包含增强方法的Bean,
<aop:before>将方法声明为前置增强,
<aop after-returning>将方法设置为后置增强方法,并通过returning属性指定需要注入返回值的属性名。

总结:以上示例中,业务代码和日志代码是完全分离的,经过AOP的配置以后,不做任何代码上的修改就在addUser()方法前后实现了日志输出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值