小汤学编程之JavaEE学习day10——Spring

在这里插入图片描述

一、Spring简介
1.特点     2.核心特性     3.两大核心
二、Spring环境搭建
1.导包     2.准备数据库和表、实体类     3.定义dao层接口和接口映射文件     4.编写测试类,获取SqlSession实例,执行已映射语句
三、Spring IOC(控制反转)
1.什么是IOC     2.IOC容器的种类     3.什么是Bean     4.Bean的初始化方式     5.Bean的作用域     6.Bean的继承
四、Spring DI(依赖注入)
1.注入方式     2.数据注入     3.懒加载     4.自动装配
五、Spring EL表达式
1.SpringEL属性调用     2.SpringEL方法调用     3.Spring操作符     4.SpringEL操作List、Map集合取值
六、自己动手实现一个Spring IOC/DI 功能
七、Spring AOP(面向切面编程)
1.什么是AOP     2.面向切面的组成部分     3.SpringAOP搭建     4.Spring AOP原理之代理模式     5.Spring事务传播特性     6.Spring AOP事务     7.事务的三种实现方式     8.常用注解


一、Spring简介

在这里插入图片描述

1.特点
  • Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。
  • Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。
  • Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。
  • Spring框架是通过模块化的方式构成,允许我们只使用需要的部分
2.核心特性

可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。

3.两大核心
  • IOC/DI 容器/依赖注入
  • AOP 面向切面思想


二、Spring环境搭建

  • 导入依赖包
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.3.2</version>
</dependency>
  • 编写核心配置文件
    spring.xml文件,里面主要写要托管给容器的类的路径,如:
<bean id="a" class="com.blb.A" />
  • 编写测试类
public class Demo {
    public static void main(String[] args){
		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
		B b = classPathXmlApplicationContext.getBean(B.class);
	}
}


三、Spring IOC(控制反转)

1.什么是IOC

控制反转IoC(Inversion of Control),是一种设计思想。没有IoC的程序中我们使用面向对象编程对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,由Spring来管理应用中所有对象的生命周期。
在这里插入图片描述

IOC的主要目的是为了解耦。

2.IOC容器的种类
BeanFactory容器

这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。BeanFactory 和相关的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。

在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。

Application Context容器

Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文

Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。

ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

常用的实现说明
FileSystemXmlApplicationContext该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
ClassPathXmlApplicationContext该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
WebXmlApplicationContext该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
3.什么是Bean

被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。

被IOC容器管理的对象。

4.Bean的初始化方式
构造函数初始化

使用构造方法初始化。

静态工厂初始化

spring.xml:

<bean id="b" class="com.tc.demo1.StaticFactory" factory-method="createB" />

StaticFactory.java:

public class StaticFactory {
    public static B  createB(){
		// 构造前后都可以插入操作
        return new B();
    }
}
实例工厂初始化

spring.xml:

<bean id="factory" class="com.blb.Factory" />
<bean id="b" factory-bean="factory"  factory-method="createB" />

Factory.java:

public class Factory {
    public B  createB(){
		// 构造前后都可以插入操作
        return new B();
    }
}
5.Bean的作用域
作用域说明
singleton单例模式,在IOC容器中仅存在一个实例
prototype多例模式,每次从IOC容器调用Bean时,都返回一个新的实例
request每次Http请求都会创建一个新的Bean
session同一个会话共享一个Bean,不同的会话使用不同的Bean
application一般用于portlet应用环境

后面三种作用域仅适用于WebApplicationContext环境。

6.Bean的继承

子 bean 的定义继承父定义的配置数据,子定义可以根据需要重写一些值,或者添加其他值。
总的来说,Bean的继承类似于Java的继承。
如:

<bean id="testA" class="com.blb.entity.Person" >
    <property name="id" value="123" />
    <property name="username" value="zhangsan" />
</bean>
<bean id="testB" class="com.blb.entity.Person" parent="testA">
    <!--“重写”父bean testA 的id属性-->
    <property name="id" value="321" />
    <!--  子bean也可以拥有自己的属性 -->
    <property name="sex" value="" />
</bean>


四、Spring DI(依赖注入)

依赖注入就是通过IOC容器将类之间的关系在容器内部绑定,使得类与类之间进一步解耦,让类更加专注于业务本身而不用处理其他对象的生命周期。无论是IOC或者是DI其实都是为了解耦,前者是为了将类的生命周期交给IOC容器统一管理,后者处理类与类的关系,而这些动作都将在容器内完成。

1.注入方式
Set方法注入

B.java:

@Data
public class B {
    private A a;
    
    // 基于set方法的依赖注入
    public void setA(A a) {
        this.a = a;
    }

    public void say(){
        a.say();
    }
}

A.java:

@Data
public class A {
    public void say(){
        System.out.println("I am A!");
    }
}

spring.xml:

<!--  构造函数实例化  -->
<bean id="a" class="com.blb.A" />

<bean id="b" class="com.blb.B" >
	<property name="a" ref="a"></property>
</bean>
构造方法注入

B.java:

@Data
public class B {
    private A aa;

    // 基于构造方法的依赖注入
    public B(A aa){
        this.aa = aa;
    }
    public void say(){
        aa.say();
    }
}

A.java:(同Set方法注入)
spring.xml:

<!--  构造函数实例化  -->
<bean id="a" class="com.blb.A" />

<bean id="b" class="com.blb.B" >
	<constructor-arg name="aa" ref="a"/>
</bean>
接口注入

接口注入模式因为历史较为悠久,在很多容器中都已经得到应用。但由于其在灵活性、易用性上不如其他两种注入模式,因而已经退出舞台。

2.数据注入
list、map、set、props
<!--注入List集合类型-->
    <property name="names">
        <list>
            <value>Ziph</value>
            <value>Join</value>
            <value>Marry</value>
        </list>
    </property>

    <!--注入Map集合类型-->
    <property name="countries">
        <map>
            <entry key="CHINA" value="中国"/>
            <entry key="USA" value="美国"/>
            <entry key="UK" value="英国"/>
        </map>
    </property>

    <!--注入Set集合类型-->
    <property name="phones">
        <set>
            <value>110</value>
            <value>119</value>
            <value>120</value>
        </set>
    </property>

    <!--注入Properties类型-->
    <property name="files">
        <props>
            <prop key="first">One</prop>
            <prop key="second">Two</prop>
            <prop key="third">Three</prop>
        </props>
    </property>
p-namespace

在Spring2.5后引入了P名称空间(属性的方法),用于简化setter方法属性注入。

使用P名称空间,首先需要在applicationContext.xml中引入P名称空间的配置:
xmlns:p="http://www.springframework.org/schema/p"

使用方法:
p:< 属性名 >=“xxx” 引入常量值
p:< 属性名 >-ref=“xxx” 引用其它 Bean 对象

示例:

<bean id="employee2" class="cn.itcast.spring.e_di.Employee" 
		p:eid="100002" p:name="李四" p:car-ref="car"/>
c-namespace

使用c名称空间(构造器的注入),首先需要在applicationContext.xml中引入P名称空间的配置:
xmlns:p="http://www.springframework.org/schema/c"

(使用方法同p名称空间)

3.懒加载
懒加载的设置

在标签里加入lazy-init=“true/false/default”,即可设置是否懒加载。
参数值为true为懒加载,即真正调用时才加载;
参数值为false为非懒加载,即启动Spring容器就创建对象。

当scope=“prototype” (多例)时,参数为default默认为懒加载:
当scope=“singleton”(单例)时,参数为default默认为非懒加载。

懒加载与非懒加载的优缺点

懒加载:对象使用时才去创建,节省资源,但不利于提前发现错误。
非懒加载:容器启动立刻创建对象,消耗资源,利于提前发现错误。

4.自动装配

要使用自动装配只需要在标签里加上autowire="XX"的属性即可。

自动装配方式说明
no(默认)不自动装配
byName根据名称来自动装配
byType根据类型来自动装配
constructor使用构造方法来自动装配
autowire-candidate参数值为false表示该类不参与自动装配


五、Spring EL表达式

在Spring3中提供了功能强大的表达式语言,简称SpringEL。SpringEL类似于OGNL和JSF的表达式语言,能够在运行时构建复杂表达式,存取对象属性、对象方法调用等操作。

表达式格式:#{SpringEL expression}

1.SpringEL属性调用
<bean id="testA" class="com.blb.entity.Person" >
	<property name="id" value="123" />
</bean>
<bean id="testB" class="com.blb.entity.Person">
    <!--调用testA的id属性-->
    <property name="id" value="#{testA.id}" />
</bean>
2.SpringEL方法调用
<bean id="testA" class="com.blb.entity.Person" >
	<property name="id" value="123" />
</bean>
<bean id="testC" class="com.blb.entity.Person">
    <!--调用testA的getId方法-->
    <property name="id" value="#{testA.getId()}" />
</bean>
3.Spring操作符
关系运算符说明
==、eq等于
!=、ne不等于
<、lt小于
<=、le小于等于
>、gt大于
>=、ge大于等于
4.SpringEL操作List、Map集合取值
<bean id="testA" class="com.blb.entity.Person" >
    <property name="id" value="123" />
    <property name="list">
        <list>
            <value>100</value>
            <value>20</value>
        </list>
    </property>
    <property name="myMap" >
        <map>
            <entry key="name" value="admin"/>
            <entry key="age" value="100" />
        </map>
    </property>
</bean>

<bean id="testD" class="com.blb.entity.Person">
    <!--操作List、Map集合取值-->
    <property name="value" value="#{testA.list[0]}" />
    <property name="name" value="#{testA.myMap[name]}" />
</bean>


六、自己动手实现一个Spring IOC/DI 功能

使用反射+xml,实现一个IOC和DI功能(待完成)。


七、Spring AOP(面向切面编程)

1.什么是AOP

面向切面的编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象的编程(OOP)。OOP中模块化的关键单元是类,而在AOP中模块化是切面。切面使关注点(例如事务管理)的模块化可以跨越多种类型和对象。

Spring的关键组件之一是AOP框架。尽管Spring IoC容器不依赖于AOP(这意味着您不需要使用AOP),但AOP是对Spring IoC的补充,以提供功能强大的中间件解决方案。

AOP在Spring框架中用于:

  • 提供声明式企业服务。最重要的此类服务是 [声明式事务管理]。
  • 让用户实现自定义方面,并用AOP补充其对OOP的使用。
2.面向切面的组成部分
组成部分说明
切面要切入的模块代码
切入点模块要切入的地方
通知切入模块的运行时机
3.SpringAOP搭建
搭建步骤
  1. 导包:spring-context、aspectjrt、aspectjweaver
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.2</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.6</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>
  1. 配置aop:config
<bean id="aop" class="com.blb.test1.AOP" />

<aop:config>
    <!-- 切面-->
    <aop:aspect ref="aop" >
        <!-- 切入点-->
        <aop:pointcut id="myAspect" expression="execution(* com.blb.test1.User.say())" />
        <!-- 通知-->
        <aop:after method="say" pointcut-ref="myAspect" />
    </aop:aspect>
</aop:config>
  1. 测试
springAOP通知的种类
通知的种类说明
before前置通知
after后置通知
around环绕通知
throwing异常通知(切入点发生异常才执行)
returning返回通知(切入点正常返回后执行)

around的通知的切面代码较为特殊,必须要有 ProceedingJoinPoint joinPoint 参数。如:

public void say(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕头:I am AOP!");
    joinPoint.proceed();// 执行被通知的方法
    System.out.println("环绕尾:I am AOP!");
}
4.Spring AOP原理之代理模式

Spring AOP使用JDK动态代理CGLIB创建给定目标对象的代理。JDK动态代理内置在JDK中,而CGLIB是常见的开源类定义库(重新打包为spring-core)。

如果要代理的目标对象实现至少一个接口,则使用JDK动态代理。代理了由目标类型实现的所有接口。如果目标对象未实现任何接口,则将创建CGLIB代理。

静态代理

代理类中调用被代理类的方法。

动态代理

指jdk中的动态代理。

public class MyProxy implements InvocationHandler {

    private UserService userService; // 目标类

    public MyProxy(UserService userService) { // 构造方法里传入 目标类
        this.userService = userService;
    }

    public Object invoke(Object proxy, Method method ,Object[] args) throws Throwable {
        System.out.println("调用方法前");
        Object invoke = method.invoke(userService, args);
        System.out.println("调用方法后");
        return invoke;
    }
}

测试:

public class Demo {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        MyProxy myProxy = new MyProxy(userService); // 获取动态代理类对象

        UserService userService1 = (UserService) Proxy.newProxyInstance(Demo.class.getClassLoader(),
                new Class[]{UserService.class}, myProxy);
        String nameByID = userService1.getNameByID();
        System.out.println(nameByID);
    }
}
cglib代理
public class CglibProxy implements MethodInterceptor {
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用方法前");
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("调用方法后");
        return o1;
    }
}

测试:

public class Demo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(User.class);
        enhancer.setCallback(new CglibProxy());
        User user = (User) enhancer.create();
        String s = user.say("李四");
        System.out.println(s);
    }
}

spring中强制使用cglib的方法:
<aop:aspectj-autoproxy proxy-target-class="true"/>

5.Spring事务传播特性
传播特性说明
required支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择
supports支持当前事务,如果当前没有事务,就以非事务方式执行
mandatory支持当前事务,如果当前没有事务,就抛出异常
requires_new新建事务,如果当前存在事务,把当前事务挂起
not_supported以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
never以非事务方式执行,如果当前存在事务,则抛出异常
nested如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与propagation_required类似的操作
6.Spring AOP事务

示例:

<!--  事务管理器  -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 配置事务的属性 -->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
    <!--配置事务传播性,隔离级别以及超时回滚等问题 -->
    <tx:attributes>
        <tx:method name="search*" propagation="REQUIRED" />
        <tx:method name="del*" propagation="REQUIRED" />
        <tx:method name="update*" propagation="REQUIRED" />
        <tx:method name="add*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<aop:config>
	<aop:advisor advice-ref="TestAdvice" pointcut="execution(* com.blb.dao.impl.*.*(..))"></aop:advisor>
	...
</aop:config>
7.事务的三种实现方式
实现方式说明
硬编码事务传统事务管理方式,需要自己手动提交回滚事务
声明式事务使用spring aop来声明事务
注解式事务使用注解来使用事务
8.常用注解
常用注解说明
@Controller作用在Controller上,将其注入到容器
@Service作用在service层,将其注入到容器
@Repository作用在dao层,将其注入到容器
@Component作用在普通类,将其注入到容器
@Autowired默认先按byType,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常。
可以手动指定按byName方式注入,使用@Qualifier。
如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false)
@Resource默认按 byName自动注入,如果找不到再按byType找bean,如果还是找不到则抛异常,无论按byName还是byType如果找到多个,则抛异常。
可以手动指定bean,它有2个属性分别是name和type,使用name属性,则使用byName的自动注入,而使用type属性时则使用byType自动注入。
@Resource(name=”bean名字”)或@Resource(type=”bean的class”)
@Inject使用@Inject需要引用javax.inject.jar,它与Spring没有关系,是jsr330规范。
与@Autowired有互换性。
@Scope配置Bean的作用域
@Singleton在类上加上这个注解,就可以实现一个单例类
@Value用于将属性文件中的值注入到实体中

前四个注解:@Controller、@Service、@Repository、@Component
这些注解要配合<context:component-scanbase-package=”XXX”/>使用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值