Spring框架知识点(最基础的实现)
侧边栏壁纸
  • 累计撰写 61 篇文章
  • 累计收到 18 条评论

Spring框架知识点(最基础的实现)

龙流
2022-08-23 / 0 评论 / 69 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2023年09月07日,已超过229天没有更新,若内容或图片失效,请留言反馈。

Spring的优点

性能好、易于测试、代码可重用高。
Spring,是轻量级的框架,其基础版本只有2MB左右的大小。
Spring框架的核心特性是可以用于开发任何Java应用程序,但是在JavaEE 平台上构建web应用程序是需要扩展的。
Spring框架的目标是使J2EE开发变得更容易使用,通过启用基于POJO编程模型来促进良好的编程实践。
思想:例如在jdbc中实现事务控制,无法实现代码的封装,因为使用jdbc控制事务是面向对象的思想,操作事务的提交、事务的回滚是分布在业务执行过程不同条件下的;

而Sping的声明式事务是基于AOP面向切面的编程思想,

Spring Framework

Spring基础框架,可以视为Spring基础设施,基本上任何其他Spring项目都是以Spring Framework为基础的。

Spring Framework特性

·非侵入式:
使用Spring Framework开发应用程序时,Spring对应用程序本身的结构影响非常小。对领域模型可以做到零污染;
对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构,反而能将组件结构进一步简化。
这就使得基于Spring Framework开发应用程序时结构清晰、简洁优雅。
·控制反转IOC——Inversion of Control,翻转资源获取方向。把自己创建资源、向环境索取资源变成环境将资源准备好,我们享受资源注入。
·面向切面编程:AOP——Aspect Oriented Programming,在不修改源代码的基础上增强代码功能。
·容器:
Spring IOC是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化的管理,替程序员屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发效率。
·组件化: 
Spring实现了使用简单的组件配置组合成一个复杂的应用。在Spring中可以使用XML和Java注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统。
·声明式:
很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现。
·一站式:
在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且Spring旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在Spring Framework的基础上全部使用Spring,来实现。

获取IOC,通过IOC获取管理的对象案例

假如新建一个空项目 -> 要实现案例目标,获取IOC容器中的对象 -> 最基础的实现方式,用配置文件的方式,所以要新建配置文件,在resource目录下右键新建xml,如果idea右键菜单栏中没有Spring配置的xml可选项,是因为pom中还未引入spring-context的Dependency
导入maven坐标如下:spring-context 5.2.10.RELEASE稳定版
<dependencies>
  < !--基于Maven依赖传递性,导入spring-context依赖即可导入
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.10.RELEASE</version>
  </dependency>
  <!--junit测试-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
  </dependency>
</ dependencies>

1、首先配置对象到IOC容器中,有xml和注解两种方式
xml: 在Spring的xml配置文件,名字约定俗成叫applicationContext.xml,在配置文件中使用bean标签,配置id属性、class属性

<bean id="xxxx" class="全类名"></bean>

注解:@Component @Controller @Service @Repository @RestControler更多详细

2、测试用例

public class HelloWorld(){
  public void sayHello(){
    System.out.println("hello world!");
  }
}
@Test
public void test(){
  //获取IoC容器
  ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
  //获取IoC容器中的bean
  HelloWorld helloworld = (HelloWorld)ioc.getBean("helloworld");
  helloworld.sayHello();
Spring获取bean的三种方式
1、通过name获取
2、通过class type获取
3、同时通过name和type获取

如果组件类实现了接口,根据接口类型可以获取bean吗?
可以,前提是bean唯一
如果一个接口有多个实现类,这些实现类都配置了bean,根据接口类型可以获取bean吗?
不行,因为bean不唯—
依赖注入之setter注入
如我们将对象注入Spring容器中时,可以通过对象属性的getter()为属性设置属性值
如实际配置如下:可以为Student类中的属性设置属性值
<bean id="studentTwo" class="com.hlongliu.spring.pojo.Student">
  <property name="sid" value="1001"></property>
  <property name="sname" value="张三"></property>
  <property name="age" value="23"></property>
  <property name="gender" value="男"></property>
</bean>
依赖注入之构造器注入

如 实际配置如下:

<bean id="studentThree" class="com.hlongliu.spring.pojo.Student">
  <constructor-arg value="1002"></constructor-arg>
  <constructor-arg value="李四"></constructor-arg>
  <constructor-arg value="24"></constructor-arg>
  <constructor-arg value="女" name="gender"></constructor-arg>
</bean>
代理模式场景
public class CalculatorImpl implements calculator {
  @Override
  public int add(int i, int j){
    System.out.println(日志,方法: add,参数:"+i+","+j);
    int result = i + j;
    System.out.println("方法内部,result: "+result);
    system.out.println("日志,方法:add,结果:"+result);
    return result;
  }

  @Override
  public int sub(int i, int j) {
    System.out.println("日志,方法: sub,参数:"+i+","+j);
    int result - i - j;
    System.out.println("方法内部,result: "+result);
    system.out.println("日志,方法:sub,结果:"+result);
    return result;
  }
}
①现有代码缺陷
针对带日志功能的实现类,我们发现有如下缺陷:
·对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
·附加功能分散在各个业务功能方法中,不利于统一维护
②解决思路
解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。
③困难
解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。

代理模式

概念:二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来一一解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

静态代理

创建静态代理类

public class CalculatorStaticProxy implements Calculator {
  //将被代理的目标对象声明为成员变量
  private Calculator target;

  public CalculatorStaticProxy(Calculator target) {
    this.target = target;
  }

  @Override
  public int add(int i, int j){
    //附加功能由代理类中的代理方法来实现
    System.out.println("[日志] add 方法开始了,参数是:" +i + ","+ j);
    //通过目标对象来实现核心业务逻辑
    int addResult = target.add(i,j);
    System.out.println(" [日志] add方法结束了,结果是: " + addResult);
    return addResult;
  }
}

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大星重复的代码,日志功能还是分散的,没有统一管理。
提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

动态代理

动态代理有两种:
1、jdk动态代理,要求必须有接口,最终生成的代理类和目标类实现相同的接口在com.sun.proxy包下,类名为$proxy2
2、cglib动态代理,最终生成的代理类会继承目标类,并且和目标类在相同的包下

/**
*目标类接口
*/
public interface Calculator{
  
  int add(int i, int j);

  int sub(int i, int j);
  
}


/**
*目标类
*/
public class CalculatorImpl implments Calculator {

  @Override
  public int add(int i, int j){
    return i+j;
  }

  @Override
  public int sub(int i, int j){
    return i-j;
  }
  
}


/** 动态代理核心
*生产代理对象
*/
public class GenerateProxy(){
  private Object target;

  public GenerateProxy(Object target){
    this.target = target;
  }

  public Object getProxy(){
    /**
    *newProxyInstance():创建一个代理实例
    *共有三个参数
    * ClassLoad 类加载器    Class<?>[] 目标对象
    */
    ClassLoad classLoad = this.getClass().getClassLoad();
    Class<?>[] interfaces = target.getClass().getInterface();
    InvocationHandler h = new InvocationHandler(){
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //proxy代表代理对象,method代表要执行的方法,args代表执行方法的参数
        Object result = method.invoke(target,args);

        return result;
      }
    }

    return Proxy.newProxyInstance(classLoad,interfaces,h);
      
  }
}


/**
*测试
*/
public class ProxyTest{
  @Test
  public void testProxy(){
    GenerateProxy generateProxy = new GenerateProxy(new CalculatorImpl());
    Calculator proxy = (Calculator)generateProxy.getProxy();
    proxy.add(1,2);
  }
}

使用Maven快速创建基础Java项目,不选择骨架

l75n8vwh.png

设置项目基本信息

l75nbrdj.png

生成webapp资源路径

l75nluy6.png

设置配置web项目配置文件web.xml

l75no22r.png

web.xml内容

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 加载spring容器 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:spring*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>

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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--  包扫描 -->
    <context:component-scan base-package="com.dldata.home.service.impl,com.dldata.home.dao"/>
    <!--  导入数据库配置文件 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--  配置数据库 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--  创建session工厂-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>
    <!--  告诉spring mybatis接口位置-->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dldata.home.dao"/>
    </bean>
    <!--  事务管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
</beans>
0

评论 (0)

取消