Spring框架学习笔记

1. Spring框架

1.1 什么是框架?

框架(Framework):在软件设计中指为解决一个开放性问题而设计的具有一定约束性的支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分。

1.2 Spring是什么

Spring:分层的Java SE/EE full-stack 开源的轻量级Java开发框架。

Spring具有控制反转(IoC)和面向切面(AOP)两大核心。

Spring框架通过声明方式灵活地进行事务的管理,提高开发效率的质量。

Spring框架不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring框架还是一个超级粘合平台,除了自己提供功能外,和提供粘合其他技术和框架的能力。

2. Spring核心之IoC控制反转

2.1 IoC的概念

IoC:Inversion of Control,即控制反转,是一种设计思想。

IoC指:在实际的程序开发中,实例的创建不再由调用者管理,而由Spring容器创建。

思想:Spring容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码(new,反射,克隆,序列化,动态代理)转移到了Spring容器中,控制权发生了反转,这就是Spring的IoC的思想。

2.2 SpringIoC案例
2.2.1 获取Spring容器

Spring提供两种容器,分别是BeanFactory和ApplicationContext

2.2.1.1 BeanFactory

(配置的xml文件中)

<bean id="team1" class="com.dada.Team"></bean>

BeanFactory是基础类型的loC容器,是一个管理Bean的工厂,主要负责初始化各种Bean,并调用它们的生命周期方法。

BeanFactory接口由多个实现类,最常见的是org.springframework.beans.factory.xmlXmlBeanFactory,它根据XML配置文件中的定义装配Bean。(已过时)

@Test
    public void test02(){
        BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("src/main/resources/application.xml"));
        Team team = (Team) beanFactory.getBean("team1");
    }
2.2.1.2 ApplicationContext

ApplicationContext是BeanFactory的子接口,(应用上下文),不仅提供了BeanFactory的所有功能,还添加了对i18n(国际化)、资源访问、事件传播等方面的良好支持。

ApplicationContext有两个常用的实现类:

2.2.1.2.1 ClassPathXmlApplicationContext

该类从类路径 ClassPath 中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作

@Test
    public void test01(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
    }
2.2.1.2.2 FileSystemXmlApplicationContext
@Test
    public void test03(){
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("src/main/resources/application.xml");
    }

它与ClassPathXmlApplicatiaonContext的区别是:在读取Spring的配置文件时,FileSystemXMLApplicationContext不再从类路径中读取配置文件,而是通过参数指定配置文件的位置,它可以获取类路径之外的资源。

2.3 Spring容器创建对象的3种方式
  1. 使用默认的无参构造方法
  2. 使用带参的构造方法
  3. 使用工厂类

示例:

创建文件createType.xml

<?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 id="team1" class="com.dada.bean.Team"></bean>

    <!--通过带参数的构造方法,name:表示参数的名称-->
    <bean id="team2" class="com.dada.bean.Team">
        <constructor-arg name="id" value="1001"></constructor-arg>
        <constructor-arg name="name" value="火箭"></constructor-arg>
        <constructor-arg name="location" value="休斯顿"></constructor-arg>
    </bean>

    <!--通过带参数的构造方法,index:表示参数的序号-->
    <bean id="team3" class="com.dada.bean.Team">
        <constructor-arg index="0" value="1001"></constructor-arg>
        <constructor-arg index="1" value="火箭"></constructor-arg>
        <constructor-arg index="2" value="休斯顿"></constructor-arg>
    </bean>

    <!--通过工厂方法,静态方法-->
    <bean id="staticBean" class="com.dada.bean.MyFactory" factory-method="staticFun"></bean>

    <!--通过工厂方法,实例方法-->
    <bean id="factory" class="com.dada.bean.MyFactory"></bean>
    <bean id="instanceBean"  factory-bean="factory" factory-method="instanceFun"></bean>
</beans>

测试类:

    @Test
    public void test05(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("createType.xml");
    }

上面用到的Team类和Factory类:

package com.dada.bean;

public class MyFactory {
    public Team instanceFun(){
        System.out.println("Myfactory ------------- instanceFun");
        return new Team(1003,"湖人","洛杉矶");
    }
    public static Team staticFun(){
        System.out.println("MyFactory ------------- staticFun");
        return new Team(1004,"小牛","达拉斯");
    }

    public static void main(String[] args) {
        //如果不用框架,我们原本应该这样调用函数
        Team team = MyFactory.staticFun();
        Team team1 = new MyFactory().instanceFun();
    }
}

package com.dada.bean;

public class Team {
    private Integer id;
    private String name;
    private String location;

    @Override
    public String toString() {
        return "Team{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", location='" + location + '\'' +
                '}';
    }

    public Team(Integer id, String name, String location) {
        this.id = id;
        this.name = name;
        this.location = location;
        System.out.println("Team的默认构造方法被调用:id=" + id + ",name=" + name + ", location=" + location);
    }

    public Team() {
        System.out.println("Team的默认构造方法被调用:id=" + id + ",name=" + name + ", location=" + location);
    }
}
2.4 基于xml的DI
2.4.1 DI的概念与IoC的区别

DI–Dependency Injection,即依赖注入:组件之间的依赖关系由容器在运行期决定,形象的说,即由容器动态地将某个依赖关系注入到组件之中。

依赖注入的目的**并非为软件系统带来更多功能,而是为了提升组件重用的频率,**并为系统搭建一个灵活、可扩展的平台。

通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

IoC是一个概念,是一种思想,其实现方式多样。依赖注入就是其中用的比较多的一种方式。

IoC和DI是同一个概念的不同角度描述。DI是实现IoC的手段。Spring框架使用依赖注入实现IoC。

Spring容器是一个超级大工厂,负责创建、管理所以的Java对象,这些对象被称为Bean。

Spring使用DI的方式来管理Bean之间的依赖关系,使用IoC实现对象之间的解耦合。

2.4.2 注入分类
  1. 通过set方法
    def:通过setter方法传入被调用者的实例。这种注入方式简单直观,在Spring的依赖注入中大量使用。

  2. 通过构造方法
    def:在构造调用者实例的同时,完成被调用者的实例化。使用构造器设置依赖关系。

  3. 自动注入
    def:对于引用类型属性的注入,也可不在配置文件中显示的注入。可以为标签设置autowire的属性值,为引用类型属性进行隐式自动注入。(默认显示)。根据自动注入判断标准的不同,可分为如下两种

    byName:根据类型名称自动注入
    当配置文件中被调用者的bean的id值与代码中调用者bean类的属性名(测试类中引用的类名)相同时,可以使用byName方式。(容器是通过调用者的bean类的属性名与配置文件中被调用者bean的id值进行比较实现自动注入的)

    byTpye:根据类型自动注入
    配置文件中被调用者bean的class属性指定的类,要与代码中bean类的某引用类型属性同源。要么相同,要么是is-a关系(子类,或实现类)。但这样的同源的被调用bean只能有一个,多于一个,容器就不知道调用哪一个了。

示例:

使用set方法注入属性值(setservice的dao)

<bean id="teamdao" class="com.dada.dao.TeamDao"></bean>
    <bean id="teamservice" class="com.dada.service.TeamService">
        <!--使用set方法注入属性值-->
        <property name="teamDao" ref="teamdao"></property>
    </bean>

使用构造方法注入属性值

<bean id="teamService1" class="com.dada.service.TeamService">
        <!--使用构造方法注入属性值-->
        <constructor-arg name="teamDao" ref="teamdao"></constructor-arg>
</bean>

按名称自动注入(id:teamDao与类名相同)

    <!--按名称自动注入(teamservice2)-->
    <bean id="teamDao" class="com.dada.dao.TeamDao"></bean>
    <bean id="teamservice2" class="com.dada.service.TeamService" autowire="byName"></bean>
    <bean id="teamservice3" class="com.dada.service.TeamService" autowire="byName"></bean>

按类型自动注入(teamDao只能有一个)

<!--按类型自动注入(TeamService)-->
 <bean id="teamDao" class="com.dada.dao.TeamDao"></bean>
    <bean id="teamService4" class="com.dada.service.TeamService" autowire="byType"></bean>
2.5 基于注解的DI

使用注解,将不需要在Spring配置文件中声明bean实例。Spring中使用注解,需要在原有Spring运行环境基础上再做一些改变。

2.5.1 声明Bean的注解@Component

在类上添加注解@Component表示该类创建对象的权限交给Spring容器,注解的value属性用于指定bean的id值,可以省略。

@Conponent
(相当于<bean id="teamDao" class="com.dada.dao.TeamDao"></bean>)
@Conponent("teamDao")
@Conponent(value="teamDao")
@Repository
@Repository("teamDao")
@Repository(value="teamDao")
效果是等同的,依次类推

@Component不指定value属性,bean的id是类名的首字母小写(默认为类名的首字母小写)

@Repository:用于dao实现类的注解(持久层对象)

@Service:用于service实现类的注解(业务层对象)

@Controller:用于controller实现类的注解(控制层对象)

这三个注解与@Component都可以创建对象。是对@Component注解的细化,标注不同层的对象。

2.5.2 包扫描

需要在Spring配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。

顶部添加头文件导包:

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd

然后声明:

<context:component-scan base-package="com.dada.dao"></context:component-scan>

如果要导多个包,可以添加多条,也可以在一条中用 , ; 和 空格 分隔开。

2.5.3 属性注入@Value

需要在属性上使用注解@Value

该注解的value属性用于指定要注入的值。

使用该注解完成属性注入时,类中无需setter;如果有setter,也可以加到setter上。

    @Value("1001")
    private Integer id;
    @Value("湖人队")
    private String name;
    @Value("洛杉矶")
    private String location;
2.5.4 byType自动注入@Autowired

需要在引用属性上使用注解@Autowired,

该注解默认使用按类型自动装配Bean的方式,

使用该注解完成属性注入时,类中无需setter;同样,若有setter,也可以加在setter上

2.5.5 byName自动注入@Autowired 和 @Qualifier

需要在引用属性上联合使用注解@Autowired 与 @Qualifier。

@Qualifier的value属性用于指定要匹配的Bean的id值。类中无需set方法,也可加到set方法上

@Autowired还有一个属性required,默认true,当匹配失败后,会终止程序运行;若将其至为false,则匹配失败,将被忽略,为匹配的属性值为null。

2.5.6 自动注入@Resource

jdk 1.6 之后提供的注解类型,@Resource注解默认按名称注入。

3.Spring 核心之AOP切面编程

3.1 什么是AOP

AOP:Aspect Oriented Programming,意为面向切面编程,是通过预编译和运行期动态代理实现程序功能统一维护的一种技术。

作用:在不修改源码的情况下,程序运行期间对方法进行功能增强(开闭)

开发中:各自做自己擅长的事情,运行的时候将服务性代码置入到核心业务中。Spring工厂将自动实现这个过程。

3.2 AOP的实现机制

代理:自己不做,找别人帮你做
代理模式:在一个原有功能的基础上添加新的功能
分类:静态代理和动态代理

3.3 静态代理
3.3.1 原有方式:核心业务和服务方法都编写在一起
3.3.2 基于类的静态代理

将服务性代码从核心业务中分离出来
要求:继承被代理的类
弊端:代理类每次只能代理一个类

3.3.3 基于接口的静态代理

为核心业务创建一个接口,通过接口暴露被代理的方法
要求:代理类和被代理类都实现同一个接口

3.3.4 总结静态代理

1)可以做到在不修改目标对象功能的前提下,对目标对象功能扩散
2)缺点:因为代理对象,需要与目标对象实现一样的接口,所以会有很多代理类,类太多,一旦接口增加方法,目标对象与代理对象都要维护

3.4 动态代理

静态代理:要求代理类一定存在
动态代理:程序运行的时候,根据要被代理的对象动态生成代理类
类型:
1. 基于JDK的动态代理(目标对象要有实现接口)
2. 基于CGLIB的动态代理(目标对象没有实现接口,也叫做子类代理,在内存中构建一个子类对象从而实现对目标对象功能的扩展)

JDK与CGLIB的区别

1)JDK的动态代理有一个限制:使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现的接口,就可以用CGLIB实现。
2)CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口,它广泛地被许多AOP的框架使用,例如SpringAOP,为它们提供方法的interception。
3)CGLIB包的底层是通过使用一个小而块的字节码处理框架ASM,来转换字节码并生成新的类。

3.5 Spring AOP
3.5.1 相关概念

Spring的AOP实现底层就是对动态代理的代码进行了封装,封装后只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。

3.5.2 AspectJ对AOP的实现

对于AOP这种编程思想,很多框架都进行了实现。Spring就是其中之一。可以先向切面编程。

AspectJ也实现了AOP的功能,且其实现方式更为简洁而且支持注解式开发。

Spring中使用AOP时,一般使用AspectJ的实现方式

3.5.3 AspectJ的切入点表达式
AspectJ 定义了专门的表达式用于指定切入点。 表达式的原型如下: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?) 说明:modifiers-pattern] 访问权限类型 ret-type-pattern 返回值类型 declaring-type-pattern 包名类名 name-pattern(param-pattern) 方法名(参数类型和参数个数) throws-pattern 抛出异常类型 ?表示可选的部分
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值