admin

Spring笔记
SpringSpring是分层的轻量级开源框架。以ioc(反转控制)和aop(面向切面编程)为内核,提供了展现层 ...
扫描右侧二维码阅读全文
19
2019/08

Spring笔记

Spring

Spring是分层的轻量级开源框架。以ioc(反转控制)和aop(面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多 著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架

优势

  • 方便解耦,简化开发
  • AOP编程支持
  • 声明式事务的支持
  • 方便程序调试
  • 方便集成各种框架
  • 降低javaee api的使用难度

Spring体系结构

IOC

耦合

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。

分类:
(1) 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另 一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
(2) 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大 量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
(3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传 递该全局变量的信息,则称之为外部耦合。
(4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进 行适当的动作,这种耦合被称为控制耦合。
(5)标记耦合 。若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和 C 之间 存在一个标记耦合。
(6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形
式,系统中一般都存在这种类 型的耦合,因为为了 完成一些有意义的 功能,往往需要将某 些模块的输出数据作 为另 一些模块的输入数据。
现的。
(7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的

工厂模式

在获取对象时,采用new的方式,是主动的

工厂模式,在获取对象时,向工厂请求,通过工厂查找或者创建对象

IOC的作用:削减计算机程序的耦合

BeanFactoryApplicationContext的区别:

BeanFactory 才是 Spring 容器中的顶层接口。
ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的区别:

  • ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
  • BeanFactory:什么使用什么时候创建对象。

ApplicationContext 接口的实现类

ClassPathXmlApplicationContext: 它是从类的根路径下加载配置文件 推荐使用这种

FileSystemXmlApplicationContext: 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

AnnotationConfigApplicationContext:当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

bean标签

作用:用于配置对象让spring来创建

属性:

id:给对象在容器中提供一个唯一标识。用于获取对象。

class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。

  • singleton :默认值,单例的.
  • prototype :多例的.
  • request :WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中.
  • session :WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中.
  • global session :WEB项目中,应用在Portlet环境.如果没有Portlet环境那么globalSession 相当于 session.

init-method:指定类中的初始化方法名称。

destroy-method:指定类中销毁方法名称。

bean的作用范围和生命周期

单例对象:scope="singleton" 一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:

 对象出生:当应用加载,创建容器时,对象就被创建了。
 对象活着:只要容器在,对象一直活着。
 对象死亡:当应用卸载,销毁容器时,对象就被销毁了。

多例对象:scope="prototype" 每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。

### 实例化bean的三种方式
(1) 默认无参构造函数:

<bean id="accountDao" class="com.qing.dao.impl.AccountDaoImpl"></bean>

(2) 静态工厂方法

public class saticFactory {
  public static IAccountService createAccountService(){
      return new AccountServiceImpl();
  }
}
<bean id="accountService" class="com.qing.saticFactory" factory-method="createAccountService"></bean>

(3)使用实例工厂的方法

  <bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean> <bean id="accountService"
factory-bean="instancFactory" factory-method="createAccountService"></bean>

依赖注入

依赖注入:Dependency Injection。它是spring框架核心ioc的具体实现。

构造函数注入

要求:
类中需要提供一个对应参数列表的构造函数。
涉及的标签:
constructor-arg属性:

  • index:指定参数在构造函数参数列表的索引位置
  • type:指定参数在构造函数中的数据类型
  • name:指定参数在构造函数中的名称 用这个找给谁赋值
  • value:它能赋的值是基本数据类型和 String 类型
  • ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
public class AccountServiceImpl implements IAccountService {
    private String name;
    public AccountServiceImpl(String name){
        this.name = name;
    }
    public List<Account> findAllAccount() {
        return null;
    }

    public Account findAccountById(Integer accountId) {
        return null;
    }

    public void saveAccount() {
        System.out.println(name);
    }


}
<bean id="accountService" class="com.qing.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="test"></constructor-arg>
    </bean>

set方法注入

public class AccountServiceImpl implements IAccountService {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
 <bean id="accountService" class="com.qing.service.impl.AccountServiceImpl">
        <property name="name" value="test"></property>
    </bean>

使用p名称空间注入

此种方式是通过在 xml 中导入 p 名称空间,使用p:propertyName 来注入数据,它的本质仍然是调用类中的 set 方法实现注入功能。

    <bean id="accountService" class="com.qing.service.impl.AccountServiceImpl" p:name="test">

注入集合属性

List 结构的: array,list,set
Map 结构的 map,entry,props,prop

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
<!-- 给数组注入数据 --> <property name="myStrs">
<set>
    <value>AAA</value>
    <value>BBB</value>
    <value>CCC</value>
</set>
</property>
<!-- 注入 list 集合数据 --> <property name="myList">
<array>
<value>AAA</value>
        <value>BBB</value>
        <value>CCC</value>
    </array>
</property>
<!-- 注入 set 集合数据 --> <property name="mySet">
    <list>
        <value>AAA</value>
<value>BBB</value>
    <value>CCC</value>
</list>
</property>
<!-- 注入 Map 数据 -->
<property name="myMap"> <props>
<prop key="testA">aaa</prop> <prop key="testB">bbb</prop>
 
</props>
</property>
<!-- 注入 properties 数据 -->
<property name="myProps"> <map>
<entry key="testA" value="aaa"></entry> <entry key="testB">
            <value>bbb</value>
</entry>
        </map>
    </property>
</bean>

注解

创建对象

Component: 用于把当前类对象存入到spring容器中
属性:

value 用于指定bean的id,默认为当前类名的首字母小写

Controller: 用于表现层
Service: 用于业务层
Repository: 用于持久层

细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value 在赋值是可以不写。

注入数据

@Autowired
作用:自动按照类型注入。当使用注解注入属性时,set 方法可以省略。当有多个类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到 就报错。

@Qualifier
作用:在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和
@Autowire 一起使用;但是给方法参数注入时,可以独立使用。

@Resource
作用:直接按照 Bean 的 id 注入。它也只能注入其他 bean类型。
属性:
name:指定 bean 的 id。

@Vlaue
作用:注入基本数据类型和 String 类型数据的 属性:
value:用于指定值
注入properties中是数据时使用el表达式${}

改变作用范围

@Scope
作用:指定 bean 的作用范围。
属性:
value:指定范围的值。
取值:singleton prototype request session globalsession

xml和注解选择问题

注解的优势:配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
XML的优势: 修改时,不用改源码。不涉及重新编译和部署。

新注解

@Configuration
作用:用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用
AnnotationApplicationContext(有@Configuration 注解的类.class)。

属性:
value:用于指定配置类的字节码

@ComponentScan
作用:用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:
<context:component-scan base-package="com.itheima"/>是一样的。
属性:
basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。

@Bean
作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
属性:
name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。

@PropertySource
作用:用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
属性:
value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:

@Import
作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问
属性:
value[]:用于指定其他配置类的字节码。

AOP

AOP:全称是 Aspect Oriented Programming 即:面向切面编程。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

作用:在程序运行期间,不修改源码对已有方法进行增强。
优势:

  • 减少重复代码
  • 提高开发效率
  • 维护方便

实现方式:使用动态代理的方式

相关术语

Joinpoint(连接点 ):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的
连接点。

Pointcut(切入点 ):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。

Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Introduction(引介 ):
引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。

Target(目标对象 ):代理的目标对象。

Weaving(织入 ): 是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

Proxy(代理) :一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect(切面 ):
是切入点和通知(引介)的结合。

xml配置

  <aop:config>
        <aop:pointcut id="ptl" expression="execution( * com.qing.service.impl.*.*(..))"/>
        <aop:aspect id="facAdvice" ref="factory">
            <aop:around method="transAction" pointcut-ref="ptl"></aop:around>
        </aop:aspect>

    </aop:config>

aop:config:用于声明开始 aop 的配置

aop:pointcut:用于配置切入点表达式。就是指定对哪些类的哪些方法进行增强。
属性:
expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识

aop:aspect:用于配置切面。
属性:
id:给切面提供一个唯一标识。
ref:引用配置好的通知类 bean 的 id。

通知类型:

  • before
  • after
  • after-throwing
  • after-returning

aop:before:用于配置前置通知。指定增强的方法在切入点方法之前执行
属性:
method:用于指定通知类中的增强方法名称
ponitcut-ref:用于指定切入点的表达式的引用
poinitcut:用于指定切入点表达式
执行时间点:切入点方法执行之前执行

after-returning:用于配置后置通知
属性:
method: 指定通知中方法的名称。
pointct: 定义切入点表达式
pointcut-ref: 指定切入点表达式的引用
执行时间点:切入点方法正常执行之后。它和异常通知只能有一个执行

aop:after-throwing:用于配置异常通知
属性:
method: 指定通知中方法的名称。
pointct: 定义切入点表达式
pointcut-ref: 指定切入点表达式的引用
执行时间点:切入点方法执行产生异常后执行。它和后置通知只能执行一个

aop:after:用于配置最终通知
属性:
method: 指定通知中方法的名称。
pointct: 定义切入点表达式
pointcut-ref: 指定切入点表达式的引用
执行时间点:无论切入点方法执行时是否有异常,它都会在其后面执行。

aop:around::用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
说明:它是 spring 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。
注意:通常情况下,环绕通知都是独立使用的

切入点表达式:
execution:匹配方法的执行(常用)
execution(表达式)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))

通配符方式:
*pulic void com.qing.service.impl.AccountServiceImp.saveAccount(int id))
使用通配符
* com.qing.service.impl.*.*(..)

注解

@Aspect 注解声明为切面

@Before:把当前方法看成是前置通知。
属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@AfterReturning:把当前方法看成是后置通知。
属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用

@AfterThrowing:把当前方法看成是异常通知。

@After:把当前方法看成是最终通知。

@Around:把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

<!-- 开启 spring 对注解 AOP 的支持 -->
<aop:aspectj-autoproxy/>

@Pointcut:指定切入点表达式

不使用xml
@EnableAspectJAutoProxy

Last modification:August 20th, 2019 at 05:35 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment