Spring框架知识点

Spring简介

使用Spring可以使用简单的JavaBean实现以前EJB实现的功能, Spring是一个IOC和AOP容器框架

  • Spring是非侵入式, 开发应用过程中可以不依赖Spring的API
  • 依赖注入
  • 面向切面变成
  • 容器
  • 框架
  • 一站式: IOC和AOP的基础上可以整合企业开源框架和第三类库


public class HelloWorld {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void hello() {
        System.out.println("hello: " + name);
    }
}

public class Main {

    public static void main(String[] args) {

        // 创建HelloWorld 的一个对象
        HelloWorld helloWorld = new HelloWorld();
        // 为 name 属性赋值
        helloWorld.setName("kong");
        // 调用hello 方法
        helloWorld.hello();

    }
}
复制代码

一个简单的helloWorld程序,其中第一步创建对象 和 第二步为属性赋值可以交给Spring框架来完成

// 1. 创建Spring IOC 容器对象,容器对象会调用构造器并调用HelloWorld类中的setName方法
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 从IOC容器中获取Bean实例
        HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
// 3. 调用 hello 方法
        helloWorld.hello();
复制代码
    <bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
        <property name="name" value="Spring"></property>
    </bean>

复制代码

Spring中的IOC & DI概述

IOC是翻转资源获取的方向, 传统资源查找方式是组件向容器发起请求查找资源, 容器适时的返回资源, 应用了IOC之后,是容器主动将资源推送给它所管理的组件,组件要做的是选择合适的方式来接收资源

DI: 组件以一些预先定义好的方式接受来自容器的资源注入

// 传统方式
A a = getA();
B b = getB();
b.setA(a)
复制代码
// 使用IOC实现
B b = getB();
复制代码

IOC前生

  • 分离接口与实现
    • 报表生成器: 生成PDF 或 HTML不同类型的报表

  • 采用工厂设计模式
  • 使用反转控制 Service

##Spring配置Bean Spring属性配置细节 如何配置Bean

  • 配置方式: 基于XML文件的格式

    <bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
        <property name="name" value="Spring"></property>
    </bean>
    class: 用于创建 bean的全类名,通过反射方式在IOC中创建bean, 要求bean中必须要有无参数的构造器
    id: 用于获取容器中的bean,id值唯一
     
    复制代码
  • Bean的配置方式: 通过全类名(反射)/通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean

  • IOC容器BeanFactory & ApplicationContext概述

    • ApplicationContext 代表IOC容器 两种类型的IOC容器实现
      • BeanFactory: IOC容器的基本实现
      • ApplicationContext: 提供了更多的高级特性,是BeanFactory的子接口
      • BeanFactory是Spring框架的基础设施,面向Spring本身, ApplicationContext面向框架的使用者, 应用场合多直接使用ApplicationContext而非底层的BeanFactory
  • 依赖注入的方式:

    • 属性注入(实际中最常用):
      • 通过setter方法注入Bean的属性值或依赖的对象
      • 属性注入使用元素,使用name属性制定Bean的属性名称,value属性(或子节点指定属性值)
    • 构造器注入:
      • 通过构造方法注入Bean的属性值或依赖的对象,保证了Bean实例在实例化后就可以使用
      • 构造器注入在<constructor-arg>元素里声明属性,没有name属性
      • 混合使用index type 来指定参数的位置和参数的类型以区分重载的构造器
      // 使用value属性值类配置
      <constructor-arg value="Audi" index="2"></constructor-arg>
      // 使用value子节点来配置
      <constructor-arg type="int">
          <value>250</value>
      </constructor-arg>
      复制代码
      • 参数列表 参数类型
  • 字面值: 可以用字符串表示的值,可以通过元素标签或value属性进行注入,基本数据类型及其封装类、String等类型都可以采用字面值注入的方式

  • 使用property的ref属性建立bean之间的引用关系

    • 使用元素建立引用
    • 使用内部Bean(不能被外部Bean引用,只能在内部使用): 在属性或构造器中包含Bean的声明,这样的Bean被称为内部Bean
  • 使用集合的基本标签进行集合的配置,例如list,array,``

  • 配置Properties属性值

  • 配置独立的集合bean,以供多个bean进行引用,使用util命名空间

<util:list id="cars">
    <ref bean="car"/>
    <ref bean="car2"/>
</util:list>


复制代码

使用p命名空间来为bean的属性赋值 <bean id="person" class="com.atguigu.spring.beans.Person" p:age="30" p:name="Queen" p:cars-ref='cars'></bean>

5.Srping 自动装配

什么是自动装配: 在<bean>的autowire属性里制定自动装配的模式

  • byType(根据类型自动装配): 若出现多个类型相同的Bean,Spring无法判定,所以无法进行自动装配
  • byName(根据名称自动装配): 必须将目标Bean的名称和属性名设置的完全相同

在Person类当中定义了setter setter里面有名字的信息,

自动装配的缺点:

  • 必须所有的属性都使用自动装撇
  • 使用了装配方式只能是byName 或 byType,不够灵活
  • 一般情况下很少使用自动装配功能,明确清晰的配置文档更好

6.Spring Bean之间的关系

继承关系: 配置上的继承关系 bean配置的重用 使用<parent>关键字

依赖关系: 某些bean要在前面创建 depends-on关键字 比如要求在配置Person时,必须要有一个关联的car! 换句话说person这个bean依赖于Car这个bean

7.Spring Bean的作用域

使用scope来设定作用域 默认情况下是单例模式,相同类型的bean都是同样的 prototype: 原型 容器初始化时不创建bean实例,而在每次请求时都创建一个新的Bean实例,并返回

8.Spring使用外部属性文件

比如需要用到系统部署的细节信息(比如文件路径),这些信息需要和Spring文件分离

使用PropertyPlaceholderConfigurer的BeanFactory 后置处理器,该处理器允许用户将Bean配置的部分内容外移动到属性文件中,可以在Bean配置文件中使用 ${var}变量来从外部属性文件中加载属性,并使用这些属性来替换变量

9. Spring SpEL语句

可以使用SpEL语句进行扩展性的操作:

  • 引用类的静态属性
  • 使用SpEL 语句来应用其他的Bean、其他Bean的属性、
  • 使用运算符

10.Spring 管理Bean的声明周期

Spring允许在Bean声明周期的特定点执行定制的任务 SpringIOC 容器对Bean的声明周期进行管理的过程:

  • 通过构造器或工厂方法来创建Bean实例
  • 为Bean的属性设置值和对其它Bean的引用
  • 调用Bean的初始化方法
  • 使用Bean
  • 当容器关闭时,调用Bean的销毁方法

在Bean的声明中设置init-methoddestroy-method属性,为Bean指定 初始化和销毁方法

在类里面先将init方法(名字可以自定义,保证对应就行)定义好,
<bean id="car" class="..." init-method="init" destroy-method="destroy">

复制代码

ctx.close(): 关闭IOC容器

创建Bean后置处理器 Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理

通过工厂方法配置Bean的

静态工厂方法: 直接调用某一个类的静态方法就可以返回Bean的实例

  • class: 指向静态工厂方法的全类名
  • factory-method关键字: 指向静态工厂方法的名字
  • constructor-arg: 如果工厂方法需要传入参数,则使用constructor-arg来配置参数
<bean id="car1" class="..." factory-method="getCar">
    <constructor-arg value="audi"></constructor-arg>
</bean>
复制代码

实例工厂方法:: 先要创建工厂本身,再通过调用工厂

  • factory-bean: 指向实例工厂方法的bean
  • factory-method关键字定义工厂bean的方法
<bean id="carFactory" class="..."></bean>
<bean id="car2" factory-bean="" factory-method="..">
复制代码

11. 使用Spring的FactoryBean配置Bean

FactoryBean 是Spring提供的一个接口

  • 自定义的FactoryBean需要实现FactoryBean
  • class: 指向FactoryBean的全雷鸣
  • property: 配置FactoryBean的属性 实际返回的实例是FactoryBean的getObject() 返回的实例 便于有时候配置Bean的时候用到Spring当中的其它Bean
  • getObject()
  • getObjectType()
  • isSingleton()

13. 基于注解配置Bean

在classpath中扫描组件

  • @Component: 基本注解,标识一个Spring管理的组件
  • @Respository: 标识持久层组件
  • @Service: 标识服务层(业务层)
  • @Controller: 表现层组件 Spring默认命名策略: 使用非限定类名时,第一个字母小写, 也可以在注解中通过value属性值标识组件的名称

需要在Spring配置文件中声明<context:component-scan> 来限定扫描哪些包

指定一个需要扫描的基类包,Spring容器会扫描基类包以及其子包中的所有类,多个包可以通过逗号分隔 context:exclude-filter: 排除指定组件 context:include-filter: 包含表达式组件

14. 基于注解配置Bean2

16. Spring AOP基础

一个计算器接口,

需要完成两个额外的需求, 生成日志 + 进行验证

日志代码差不多 核心代码混乱,越来越多非业务需求,每个方法在处理 还要兼顾其他多个关注点

代码分散: 只是为了满足一个单一需求,不得不在多个模块(方法)里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有模块.

AOP方式解决

动态代理解决 代理设计模式: 使用一个代理将对象包装起来,然后用该代理对象取代原始对象,任何对原始对象的调用都要通过代理

public class ArithmeticCalculatorLoggingProxy {
    
    //要代理的对象
    private ArithmeticCalculator target;
    
    public ArithmeticCalculator getLoggingProxy() {
        ArithmeticCalculator proxy = null;
        
        // 代理对象由哪一个类加载器负责加载
        ClassLoader loader = target.getClass().getClassLoader();
        // 代理对象的类型,即其中有哪些方法
        Class[] interfaces = new Class[]{ArithmeticCalculator.class};
        // 当调用代理对象其中的方法时,需要执行的代码
        InvocationHandler h = new InvocationHandler() {
            /**
            * @param: proxy: 正在返回的代理对象,一般情况下,invoke方法中不使用
            * @param: method: 正在被调用的方法
            * @args: 调用方法时,传入的参数
            */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("invoke...");
                return 0;
            }
        };
        proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
        return proxy;
    }
}
复制代码

动态是什么意思?体现在哪里?

横切关注点方法 在应用AOP时,需要定义公共功能,但可以明确定义功能在哪里,以何种方式应用,并且不必修改受影响的类.

AOP的好处:

  • 每个事务逻辑位于一个位置,代码不分散,便于维护和升级
  • 业务模块更简洁,只包含核心业务代码

计算器加减乘除的例子:

切面: 通知: 切面中的每一个方法就是通知 连接点: 程序执行的某个特定位置 一个具体的存在 切点: 看不见 通过切点定位到特定连接点

Spring 前置通知

在配置文件中加入AOP的命名空间 xmlns:aop="..."

基于注解的方式: 在配置文件中加入如下配置: 把横切关注点的代码抽象到切面的类中 切面首先是一个Java bean,需要加入@Component注解 使用@Aspect注解标注出切面,

  • 提供5个注解来定义通知
    • @Before: 方法执行前
    • @After: 方法执行后
    • @AfterReturning: 通知方法在目标方法返回后调用
    • @AfterThrowing: 通知方法在目标方法抛出异常后调用
    • @Around: 环绕

execution() * 可以表示任意修饰符及任意返回值

20. Spring切面的优先级

使用@Order 指定切面的优先级,值越小,优先级越高

21. 重用切点表达式

重新用execution 那一坨东西 定义一个方法,用于声明切入点表达式, 之后再用到该切点的地方就直接调用该方法即可声明对应切点

@Pointcut("...")
public void declareJointPointExpression(){}
复制代码

22. 基于配置文件声明切面

<aop:config>
    <aop:aspect ref="audience">
        <aop:before
            pointcut="..." method="方法名"/>
        <aop: after-returnning
            pointcut="execution(...)"/>
    </aop:aspect>
</aop:config>

复制代码

25. Spring事务准备

必须为不同的方法重写类似的样板代码,存在大量的重复部分

public void purchase(String isbn, String username) {
    Connection conn = null;
    try {
        conn = dataSource.getConnection();
        conn.setAutoCommit(false);
        ...
        conn.commit();
    } catch (SQLException e) {
        e.printStackTrace();
        if (conn != null) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        throw new RuntimeException(e);
    } finally {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}


复制代码

编程式 声明式

Spring

配置事务管理器 启用事务注解 @Transactional

转载于:https://juejin.im/post/5c8c95aa51882544e02af8a6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值