Spring: 全功能栈的应用程序框架

一、Spring框架介绍

        Spring Framework是由Spring团队研发的模块化、轻量级开源框架。其主要目的是为了简化项目开发。下面是Spring各个模块

 Test

对应spring-test.jar。Spring提供的测试工具,可以整合JUnit测试,简化测试环节。

Core Container  

Spring的核心组件, 包含了Spring框架最基本的支撑。

Beans, 对应spring-beans.jar。Spring进行对象管理时依赖的jar包。

Core, 对应spring-core.jar,Spring核心jar包。

Context, 对应spring-context.jar, Spring容器上下文对象。

SpEL, 对应spring-expression.jar, Spring表达式语言。

 AOP :面向切面编程。

Aspects  :Aspects的具体实现为面向切面编程的另一种实现。

Instrumentation  :服务器代理接口的具体实现。  

 Messaging :集成messaging api和消息协议提供支持。

 Data Access/Integration :Spring对数据访问层的封装。

JDBC,对应spring-jdbc.jar。Spring对jdbc的封装,当需要使用spring连接数据库时使用spring-jdbc.jar需要依赖spring-tx.jar。

Transactions。对应spring-tx.jar,事务管理。

ORM,对应spring-orm.jar。 spring整合第三方orm框架需要使用的jar包,例如Hibernate框架.

 Web :Spring对javax下的接口或类做的扩展功能。

二、Spring IoC/DI 介绍

1.Spring IoC/DI

 IoC(Inversion of Control)中文名称:控制反转。也被称为DI(dependency injection )依赖注入。属于同一件事情的两个名称。

IoC/DI指的是一个过程:对象的创建仅仅通过Spring容器负责,Spring容器可以通过对象的构造方法或工厂方法进行实例化对象。在创建对象过程中,如果对象需要依赖其他对象,也可以直接在Spring容器中注入到当前对象。

整个过程中对象本身在容器中控制自己的实例化(所以叫做控制反转),通过构造方法或setter方法把依赖对象注入到属性中(所以又叫做依赖注入)。

2.Ioc/DI好处

 

 Spring IoC/DI使用后可以管理项目中相关对象,让对象管理的事情和业务分离(解耦)。同时程序员也不需要管理对象的依赖关系,所有的依赖关系交给Spring容器进行管理。

3.Ioc/DI应用场景

IoC/DI 主要作用就是管理对象的实例化和对象之间依赖关系。项目中以前需要自己实例化的层对象、框架或工具包的入口类都可以交给Spring 容器进行管理。

  • 层对象:PeopleMapper 接口代理对象、PeopleServiceImpl。

  • 框架入口类:SqlSessionFactory等。

Servlet只能被Tomcat管理(由Tomcat帮助实例化创建的),所以Spring容器是无法管理Servlet的。但是Servlet可以从Spring容器中取出对象。

三、Bean实例化的两种方式(面试题)

在Spring中实例化Bean有两种方式:

  • 通过构造方法进行实例化。默认使用无参构造。这种方式和以前new的方式是等效的。需要在XML中通过<bean>的class属性指定类的全限定路径,然后就可以实例化对象。

  • 通过工厂进行实例化。可以通过静态工厂和实例工厂进行实例化。这种方式完全是根据设计模式中工厂模式的思想而研发出的。Spring考虑到如果需要频繁实例化某个类的对象,工厂模式无疑是一个好选择。

 1.使用实例工程实例话bean

1.1.创建工厂类

实例工厂方式需要实例化工厂类。所以工厂中创建bean的方法是一个实例方法。

在项目中创建实例工厂类,并编写方法返回创建的实例对象。

public class PeopleFactory {
    People peo = new People();
    public People getInstance(){
        return peo;
    }
}

 1.2配置文件

在applicationContext.xml中先配置工厂实例,然后通过工厂实例产生自己想要的bean对象,注意bean标签中属性含义:

  • factory-bean:工厂bean的id属性值。

  • factory-method:工厂中创建bean的方法。

<!-- 创建工厂实例 -->
<bean id="factory" class="com.factory.PeopleFactory"></bean>
<!-- factory-bean:工厂对象的id    factory-method:创建当前bean的方法名称 -->
<bean id="peo2" factory-bean="factory" factory-method="getInstance"></bean>

 1.3测试

public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        People peo = ac.getBean("peo2", People.class);
        System.out.println(peo);
    }
}

2.使用静态工程实例花bean

1.创建工厂类

静态工厂和实例工厂类最主要的区别是,创建bean的方法是static修饰的。

public class PeopleStaticFactory {
    private static People peo = new People();

    public static People newInstance(){
        return peo;
    }
}

2.配置文件的配置

在applicationContext.xml中配置bean,注意bean标签中属性含义:

  • class:静态工厂类的全限定路径

  • factory-method:静态工厂中创建bean的静态方法。

之所以可以这样配置,是因为Java中静态方法是通过类名直接调用,不需要创建工厂的实例。

<bean id="peo3" class="com.factory.PeopleStaticFactory" factory-method="newInstance"></bean>

3.测试

public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        People peo = ac.getBean("peo3", People.class);
        System.out.println(peo);
    }
}

四、属性注入的两种方式

Spring中给Bean属性赋值有两种方式:

  • 构造注入(Constructor-based Dependency Injection):通过构造方法给bean的属性赋值。所以要求bean的类中必须提供对应参数的构造方法。相当于以前创建对象时new People(1,"张三");

  • 设值注入,又称setter注入(Setter-based Dependency Injection):通过Bean的setter方法赋值。所以要求Bean中属性必须提供setter方法。相当于以前的:People peo = new People(); peo.setId(1); peo.setName("张三");

1.构造注入

  • 调用有参构造方法创建对象及完成属性值的注入,必须提供有参构造方法。

  • 提供了有参构造方法,不再默认提供无参构造方法,不使用构造注入会需要使用无参构造方法创建对象,需要提供无参构造方法。

配置bean

 在配置文件applicationContext.xml中可以通过<bean>的子标签<constructor-arg>设置构造方法中一个参数的值。

下面代码使用了type进行确认到底给构造方法哪个参数赋值。也可以尝试使用其他的属性来确认参数。  

<bean id="peo4" class="com.pojo.People">
    <constructor-arg type="int" value="1"></constructor-arg>
    <constructor-arg type="java.lang.String" value="张三"></constructor-arg>
</bean>

 2.设置注入(setter注入)

  • 调用set方法完成属性值的注入,必须提供set方法。

  • Setter注入一般都是结合无参构造方法一起使用。所以类中有无参构造方法和set方法。

配置bean:

  1. 重新配置了一个bean标签,并设置id=“peo5”。

  2. 通过<property>标签调用类的setter方法。

    • name:属性名称。

    • value:属性值。

    • ref:引用另一个bean标签的id属性。

<bean id="peo5" class="com.pojo.People">
    <property name="id" value="2"></property>
    <property name="name" value="李四"></property>
</bean>
 2.1其他引用数据类型的属性注入
1.Set类型
<bean id="peo7" class="com.pojo.People">
    <property name="hover">
        <set>
            <value>aaa</value>
        </set>
    </property>
</bean>
2.List类型
<bean id="peo7" class="com.pojo.People">
    <property name="subjects">
        <list>
            <value>java</value>
        </list>
    </property>
</bean>
3.Array类型
<bean id="peo7" class="com.pojo.People">
    <property name="teachers">
        <array>
            <value>小明</value>
        </array>
    </property>
</bean>
4.Map类型
<bean id="peo7" class="com.pojo.People">
    <property name="phone">
        <map>
            <entry key="姓名" value="18612345678"></entry>
        </map>
    </property>
</bean>
5.Null类型
<bean id="peo7" class="com.pojo.People">
    <property name="phone">
        <null></null>
    </property>
</bean>
6.引用其他Bean

        如果需要引用其他Bean,直接在property标签中使用ref引用就可以。使用子标签ref也可以,但是没有直接用ref属性的方式简单。

<bean id="tea" class="com.pojo.Teacher"></bean>
<bean id="peo8" class="com.pojo.People">
    <property name="teacher" ref="tea"></property>
</bean>

五、自动注入

1.属性值自动注入

自动注入指的都是bean之间的自动注入。能够自动注入必须保证Spring 容器中包含能被自动注入的bean。

在Spring中,允许Bean的自动注入,有两种方式进行配置。

  • 在根标签<beans>中配置default-autowire属性,自动注入的策略,可取值有5个。

    1. default:默认值,不自动注入。(使用在bean标签中有其它含义)

    2. no:不自动注入。

    3. byName:

      1. 通过名称自动注入。名称:属性名与bean的id属性值。

      2. 会自动寻找容器中与注入值属性名同名的id属性值的bean进行注入。

      3. 底层为setter注入,设值注入。

    4. byType:

      1. 通过类型自动注入。类型:属性类型与bean的class类型。

      2. 会自动寻找容器中与注入值类型相同的bean进行注入。如果有多个相同类型的bean注入会出现异常。

      3. 底层为setter注入,设值注入。

    5. constructor:

      1. 通过构造方法进行注入。调用有参构造方法完成对象创建及属性自动注入。

      2. 寻找bean的有参构造方法中只包含需要注入属性参数的构造方法。自动属性注入。

      3. 底层为构造注入。

  • <bean>标签中配置autowire属性,和default-autowire取值相同。

    • default:使用上级标签<beans>的default-autowire属性值。

    • default-autowire表示全局的配置。如果autowire和default-autowire同时存在,autowire生效。

<bean id="peo" class="com.pojo.People" autowire="byType"></bean>

六、bean标签的scope属性

Spring中<bean>的scope控制的是Bean的有效范围。

一共有6个可取值

singleton:默认值。bean是单例的,每次获取Bean都是同一个对象。

prototype:bean时原型的,每次获取bean都重新实例化。

request:每次请求重新实例化对象,同一个请求中多次获取时单例的。

session:每个会话内bean是单例的。

application:整个应用程序对象内bean是单例的。

websocket:同一个websocket对象内对象是单例的。

里面的singleton和prototype在Spring最基本的环境中就可以使用,不需要web环境。

但是里面的request、session、application、websocket都只有在web环境才能使用。

<bean id="people" class="com.pojo.People" scope="singleton"></bean>

Spring 中 Bean是否是线程安全的?

1. 如果bean的scope是单例的,bean不是线程安全的。

2. 如果bean的scope是prototype,bean是线程安全的。

七、单例设计模式

单例设计模式:保证某个类在整个应用程序中只有一个对象。

单例写法分为两种:饿汉式、懒汉式。

1.饿汉式

/*
    单例:希望类只有一个
    核心思想:
        1. 构造方法私有
        2. 对外提供一个能够获取对象的方法。

    饿汉式:
        优点:实现简单
        缺点:无论是否使用当前类对象,加载类时一定会实例化。
 */
public class Singleton {
    // 之所以叫做饿汉式:因为类加载时就创建了对象
    private static Singleton singleton = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return singleton;
    }
}

 2.懒汉式

/**
 * 核心思想:
 * 1. 构造方法私有。
 * 2. 对外提供一个能够获取对象的方法。
 *
 * 懒汉式优点和缺点:
 *  优点:
 *      按需创建对象。不会在加载类时直接实例化对象。
 *  缺点:
 *      写法相对复杂。
 *      多线程环境下,第一次实例化对象效率低。
 */
public class Singleton2 {
    //懒汉式:不会立即实例化
    private static Singleton2 singleton2;
    private Singleton2() {}
    public static Singleton2 getInstance() {
        if (singleton2 == null) {// 不是第一次访问的线程,直接通过if判断条件不成立。直接return
            synchronized (Singleton2.class) {
                if(singleton2==null) {// 防止多个线程已经执行到synchronized
                    singleton2 = new Singleton2();
                }
            }
        }
        return singleton2;
    }
}

八、Spring 循环注入问题

1.概念

循环注入即多个类相互依赖,产生了一个闭环。

        当两个类都是用构造注入时,没有等当前类实例化完成就需要注入另一个类,而另一个类没有实例化完整还需要注入当前类,所以这种情况是无法解决循环注入问题的的。会出现BeanCurrentlyInCreationException异常。

        简单来说,就是A的某个field依赖了B的实例对象,同时B的某个field依赖了A的实例对象,这种情况为循环依赖。

2.解决循坏依赖问题

         如果两个类都使用设值注入且scope为singleton的就不会出现问题,可以正常执行。因为单例默认下有三级缓存(DefaultSingletonBeanRegistry),可以暂时缓存没有被实例化完成的Bean。

  • 一级缓存(singletonObjects):存放实例化,属性注入,初始化完成的对象。

  • 二级缓存(earlySingletonObjects):存放早期暴露出来的Bean对象,属性还未填充完整。

  • 三级缓存singletonFactories():存放bean创建工厂,以便于后面扩展有机会创建代理对象。

 

 3.单例模式创建对象的步骤

Spring的单例对象的初始化主要分为三步:

  1. 实例化:其实也就是调用对象的构造方法实例化对象。

  2. 注入:填充属性,这一步主要是对bean的依赖属性进行填充。

  3. 初始化:属性注入后,执行自定义初始化操作。

 

九、BeanFactory和ApplicationContext

 1.BeanFactory接口

BeanFactory是Spring中的顶级接口,接口中定了Spring容器最基本功能。是Spring IoC的最核心接口。

 BeanFactory是在调用getBean方法的时候才实例化Bean。(懒汉式)

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xbdr = new XmlBeanDefinitionReader(factory);
xbdr.loadBeanDefinitions(new FileSystemResource("C:\IdeaWS\spring_day01\src\main\resources\application.xml"));
Object teacher = factory.getBean("aa");

2.ApplicationContext接口

ApplicationContext是BeanFactory的子接口。所以要比BeanFactory的功能更加强大,除了BeanFactory的功能,还包含了:

  • AOP 功能

  • 国际化(MessageSource)

  • 访问资源,如URL和文件(ResourceLoader)

  • 消息发送机制(ApplicationEventPublisher)

  • Spring集成Web时的WebApplicationContext

在使用时ApplicationContext时多使用ClassPathXmlApplicationContext

ApplicationContext是在加载配置文件后立即实例化Bean。(饿汉式)

ApplicationContext applicationContext =
        new ClassPathXmlApplicationContext("applicationContext.xml");
Object teacher = applicationContext.getBean("aa");

 十、Spring整合MyBatis(非web环境)

 1.创建项目添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>mybatisspring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.16</version>
        </dependency>
        <!-- DataSource的实现类DriverManageDataSource实现所在的包 -->
        <!-- 把数据库连接操作交给Spring,后面事务才能使用Spring的声明式事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.16</version>
        </dependency>
        <!-- Spring整合MyBatis的依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
    </dependencies>
</project>

 2.创建Spring配置文件

在src/main/resources下新建applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置数据源,设置数据库连接的四个参数 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 四个参数名固定的 -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
	<!-- 
		整合包中提供的对于SqlSessionFactory的封装,可以进行相关的配置,例如 
			1. 实体类定义别名
			2. mapper接口与mapper映射文件不在同名包中,<property name="mapperLocations" value="classpath:mappers/*.xml"/>
			   通常配置在同名包中,所以可以忽略
			3. 引入mybatis配置文件 <property name="configLocation" value="classpath:mybatis.cfg.xml"/>
			   常用的配置在spring的配置文件中配置即可,特殊的配置在mybatis配置文件中配置
	-->
    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.pojo"></property>
    </bean>
    <!-- 设置扫描哪个包,进行接口绑定-->
    <!-- 所有Mapper接口代理对象都能创建出来,可以直接从容器中获取出来。 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 扫描的包 -->
        <property name="basePackage" value="com.mapper"></property>
        <!-- 和SqlSessionFactory产生联系-->
        <property name="sqlSessionFactoryBeanName" value="factory"></property>
    </bean>
</beans>

3.创建实体类

创建com.bjsxt.People

4.创建映射接口(Mapper)

public interface PeopleMapper {
    @Select("select * from people")
    List<People> selectAll();
}

十一、Spring整合web

Spring 项目不需要依赖Web环境,但是Java项目大多数是Web项目,所以Spring也支持集成到Web环境中。

        Spring 集成Web环境是通过Listener实现的,在ServletContext对象创建时加载Spring容器。Spring已经在spring-web.jar包中提供了ContextLoaderListener实现加载Spring配置文件的代码。我们只需要在web.xml配置<listener>标签让ContextLoaderListener生效,并且告诉ContextLoaderListener加载Spring配置文件的路径即可

 1.配置监听器

在web.xml中配置监听器,让web项目启动时自动创建Spring容器对象(WebApplicationContext)。

上下文参数名param-name的值是固定的contextConfigLocation。这个值是监听器需要获取的值。

上下文参数值需要带有classpath,表示加载类路径内容。target/classes目录内容。

classpath*:表示当前项目依赖的jar中资源也会寻找。

classpath:后面的值支持星号。例如applicationContext-*.xml表示加载所有以applicationContext-开头的xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!-- 监听ServletContext对象,对象创建时会加载Spring的配置文件,创建Spring容器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
期待着您的参与 DELPHI社群中开源项目少之又少,我们可不可以自己组织?我们可不可以一起探讨?小弟不才,斗胆写下几行代码,来这里期待抛砖引玉。 我们身边,每天都有无数的项目开工,然后是老板对进度的紧追不舍,项目经理程序员加班的无奈,再然后或许是成功的喜悦或许是失败的哀愁,但不管结果如何,所有人心中此时最想要的,可能是好好的睡上一觉。 这无数的项目,他们有没有共同点?我们是不是一直在做重复发明轮子的蠢事?Delphi让我们搭建一个程序变得容易,我希望通过我们的努力,让我们搭建一个项目更容易,利用我们可以想到的任何办法,不管是框架源代码、模版文档、代码生成工具甚至是我们手把手经验的交流,我们的目标就是让一个项目开发更加的容易、让一个项目成功更加的容易。 这样的工作是激动人心的,可是我也和大家一样,面临着手头上项目的压力,为了能够对得起那份薪水,我只能够在下班的时间里做这些。但一个人精力太有限了,uPattern是一个模式实现单元,没有足够的时间也没有那么多精力去实现所有的模式,于是在这份源代码里,您发现您可以使用一个用户组来登录,本来这是不允许的啊,如果您想找到原因,原来uPattern中对于合成模式的实现使用的是原始的透明方式…… 一个人的力量太有限了,一个人的才智也太有限了,如果这个小生命在我一个人的手里,也许会因为得不到充足的阳光雨露而不能茁壮成长,但是如果有您的加入,多了您的呵护,相信我们的目标才更有可能实现。 如果您是高手,那么就在这里表现您的聪明才智吧。如果您是菜鸟,来这里汲取知识吧。所有的源代码都永久性公开,如果您有什么地方不清楚或者是有更好的建议,您也可以直接联系我。 ―――――――――――――――――――――――――――――――――― 这是一个应用程序框架,现在已经完成部分框架代码与用户管理、权限管理与日志管理模块。如果您有任何的问题或者是建议可以发邮件到我的邮箱,您可以使用本源代码在您的任何应用之中(包括商业应用)。如果您想要和我们一起来发展壮大这份源代码,请您发邮件给我(Camel_163@163.com),或者是在下面留言。 ――――――――――――――――――――――――――――――――――     uClasses------------------------------在这里定义应用程序中的基础类     uPattern------------------------------几个模式的DELPHI实现或者定义     uAppUtils-----------------------------应用程序工具单元     uAppSet-------------------------------应用程序设置接口声明单元     uAppSetIniFile------------------------应用程序设置IniFile实现单元     uException----------------------------异常统一处理单元     uAppFactory---------------------------应用程序工厂,本工厂生产出来的就是一个一般的应用程序     uAuthAppFactory-----------------------应用程序工厂,本工厂生产出来的就是拥有权限管理、日志及用户管理的程序     ufrmAppBase---------------------------窗口基类     ufrmAppDlgBase------------------------对话框窗口基类    用户、权限与日志管理单元     Role----------------------------------权限与用户管理主要的实现单元     Log-----------------------------------日志管理单元     ufrmRoleManager-----------------------权限管理主用户界面     ufrmLogin-----------------------------用户登录界面     ufrmChangePassword--------------------更改用户密码     ufrmLog-------------------------------日志查看界面     CommandRegister-----------------------模块注册中心
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值