这篇Spring框架,我吹不动了

Spring : 春天 —>给软件行业带来了春天 

为什么命名为“春天”,因为spring框架的出现,春天代表万物复苏,象征程序猿的好日子来了。

2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。

2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。

很难想象Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。这就很离谱,我也想变成他一样的人。

Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

官网 : http://spring.io/

官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/

GitHub : https://github.com/spring-projects

一.Spring框架介绍

1.概述

1.轻量级,开源的JavaEE框架。

2.解决企业开发的复杂性

3.两个核心部分 IOC(控制反转)AOP (面向切面)

2.特点

1.方便解耦,简化开发

2.AOP编程的支持

3.方便程序的测试,集成Junit

4.方便整合其他各种优秀的框架

5.声明事务的支持

6.降低JavaEE API的使用难度

7.Java源码是学习的经典案例

3.入门案例

1.创建Maven,引入Maven坐标 (spring-core)(spring-aop)(spring-context)(spring-expressio)(common-logging)(junit)

2.创建一个普通的类,在这类中创建一个普通的方法

3.创建spring配置文件bean.xml,在配置文件中配置创建的对象

4.创建测试类


二.IOC容器

1.定义

IOC为什么叫做”控制反转“,控制反转是面向对象编程的设计原则,可以减少计算机中代码的耦合度。其中最常见的方式叫做 DI(依赖注入)目的就是把创建对象的过程交给Spring进行管理

2.实现对象间调用的三种方式:

1.传统Java对象之间的调用

2.设计模式中的 ”工厂模式“ :工厂模式(三种)详解及源码_CSDNzgcxy的博客-CSDN博客

3.IOC底层原理实现的三种技术:xml解析、工厂模式、反射

IOC的过程

1.创建xml配置文件,配置创建的对象

<bean id="stu" class="spring.Student1"></bean>

2.创建反射类,通过反射机制创建对象

3.IOC接口的介绍

A.BeanFactory

IOC容器的基本实现,是spring内部的使用接口不提供给开发人员进行使用。

特点:加载配置文件时,不会创建对象,获取对象时才去创建对象。

BeanFactory beanFactory=new ClassPathXmlApplicationContext("bean.xml");//加载配置文件时不去创建对象

Student2 student2=(Student2) beanFactory.getBean("stu");//此时才开始创建对象

B.ApplicationContext

ApplicationContext是BeanFactory的子类,提供了更多更强大的功能(一代更比一代强),提供给开发人员使用

特点:加载配置文件时就会创建对象

ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");//加载配置文件时就创建对象
Student2 student2=(Student2) applicationContext.getBean("stu");

C.ApplicationContext三大常用实现类分别是:


A、ClassPathXmlApplicationContext。(可以加载类路径下的配置文件。要求配置文件必须是在类路径下,不在类路径下加载不了)
B、FileSystemXmlApplicationContext。(可以加载磁盘任意路径下的配置文件,但是必须要有访问权限)
C、AnnotationConfigApplicationContext。(用于读取注解创建容器)

D.BeanFactory和ApplicationContext的区别:

BeanFactory:
①、 在构建核心容器时,采用延迟加载的方式创建对象。(即:什么时候根据ID获取对象了,什么时候才真正的创建对象)。
②、是Spring容器中的顶层接口。

ApplicationContext:
①、 在构建核心容器时,采用立即加载的方式创建对象。(即:只要一读取完配置文件马上就创建配置文件中配置的对象)。
②、是BeanFactory的子接口。


 4.IOC操作Bean管理

一.什么是Bean管理?

1、Spring创建对象

2、Spring注入属性

A.基于XML方式

1.基于XML方式创建对象

a、基本描述

在Spring配置文件中,使用Bean标签,标签里添加相应的属性,就可以实现对象的创建。

在Bean标签里包含了许多的属性

创建对象时,默认也是创造无参构造方法完成对象的创建


b、Bean标签常用的的几个属性介绍

1.id :给对象在容器中提供一个唯一标识。用于获取对象,不能添加特殊符号。

2.class:指定类的全限定类名。用于反射创建对象。指向classpath下类定义所在位置,默认情况下调用无参构造函数

3.name:name是bean的名称标识,在网上看到有的文章说name可以重复,但是我在Srping 4.0.4.RELEASE测试中,bean标签的name属性也是不能重复,且id和name属性也不能重复,name标签应该等同于id属性。

4.scope:指定对象的作用范围

  1. A、singleton: 单例的(默认值)。
  2. B、prototype:多例的。
  3. C、request:作用于web应用的请求范围。
  4. D、session:作用于web应用的会话范围。
  5. E、global session:作用于集群环境的会话范

5.init-method

init-method属性是bean的初始方法,在创建好bean后调用该方法。

6.destory-method

destory-method属性是bean的销毁方法,在销毁bean之前调用该方法,一般在该方法中释放资源


c、Bean的作用域及生命周期

(1)单例对象:scope="singleton"

<bean id="stu" class="spring.Student1" scope="singleton"></bean>

一个对象只有一个应用实例 ,作用范围就是整个引用。加载Spring配置文件时就会创建对象,默认为单例。

生命周期:

  1. 对象出生:当应用加载,创建容器时,对象就被创建了
  2. 对象活着:只要容器存在,对象就一直存在
  3. 对象死亡:当容器销毁或应用卸载,对象销毁

 (2)原型对象:scope="prototype"

<bean id="stu" class="spring.Student1" scope="prototype">

 每次访问对象时,都会重新创建对象实例,在调用getBean方法时就会创建一个多实例的对象

 生命周期:

对象出生:当使用对象时,创建新的对象实例

对象活着:只要对象还在被使用,就一直存在

对象死亡:当对象长时间不使用,就会被Java垃圾回收站回收


d、工厂Bean(FactoryBean)

普通Bean:在配置文件定义的类型和返回类型一致

工厂Bean:在配置文件定义的类型可以和返回类型不一致

工厂Bean的实现:

首先先写一个Student的封装类,随便写几个属性

然后创建一个StudentFactoryBean去实现 AbstractFactoryBean这个接口

重写getObjectType、createInstance方法

public class StudentFactoryBean extends AbstractFactoryBean<Object>
{
    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }
    @Override
    protected Object createInstance() throws Exception {
        return new Student(1, "Ninja", "s90");
    }
    @Override
    public String toString() {
        return "StudentFactoryBean{}";
    }
}

 然后再写一个XML文件

<bean name="studentFactory" class="spring.StudentFactoryBean" />

 最后写一个测试类测试一下

public class Bootstrap
{
    public static void main(String[] args){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                new String[]{"Student.xml"}, false);

        applicationContext.setAllowBeanDefinitionOverriding(false);
        applicationContext.refresh();

        // 生成工厂类生成的具体实体类,值的是studentFactory生成的类
        Student student = (Student)applicationContext.getBean("studentFactory");
        System.out.println(student.toString());

        // 名字加了一个& 获取的是studentFactory本身
        StudentFactoryBean studentFactoryBean = (StudentFactoryBean) applicationContext.getBean("&studentFactory");
        System.out.println(studentFactoryBean.toString());
    }
}

结果应该和大家预想的一致

Student{id=1, name='Ninja', classes='s90', rmark='null', list=null, map=null, prop=null, book=null}
StudentFactoryBean{}

讲到这里就得来讲一下Bean工厂和工厂Bean的区别了

 BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,

FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类.

区别:BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的

但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似 


e、Bean的生命周期

 定义:对象创建的过期到对象销毁的过程称为Bean的生命周期

生命周期过程:

1、通过构造器创建bean实例(无参构造)

2、调用set方法为bean设置属性

3、调用bean的初始化方法

4、bean对象获取使用

5、容器关闭,调用bean的销毁方法

Bean的生命周期(可怜只有七岁)

1、通过构造器创建bean实例(无参构造)

2、调用set方法为bean设置属性

3、把bean实例传递bean前置处理器方法postProcessBeforeInitialization

4、调用bean的初始化方法

5、把bean实例传递bean后置处理器方法postProcessAfterInitialization

6、bean对象获取使用

7、容器关闭,调用bean的销毁方法


 2、基于XML方式注入属性

DI(依赖注入)实际就是注入属性

1、注入的方式

a、使用set方法注入

b、使用构造函数注入

c、Set方法注入的另一种方式,p命名空间(简化set属性注入的方式)

<bean name="studentFactory" class="spring.StudentFactoryBean" p:username="Ninja" /></beans>

 2、注入空值和特殊符号

a、向属性值中设置控制

  <property name="name" ><null /></property>

 b、属性值中包含特殊符号

1.转义<>

2.CDATA

    <property name="id">
        <value>
            <![CDATA[<<email@qq.com>]]>
        </value>
    </property>

 3、注入属性-外部Bean

(1)创建UserService类和UserDao接口、UserDaoImp实现类

(2)在beanXml配置文件中创建对象UserService和UserDao,并且在UserService对象里注入UserDao属性

 <!--创建对象UserService-->
    <bean name="UserService" class="spring.user.UserService">
       <!-- 注入外部bean ref属性是UserDaoImp对象的id-->
        <property name="Userdao" ref="UserDaoImp"></property>
    </bean>
    <!--创建对象UserDaoImp-->
    <bean name="UserDaoImp" class="spring.user.UserDaoImp"></bean>
</beans>

(3)创建测试类,执行测试方法得到结果。

4、注入属性-内部Bean

使用场景:一对多关系 举例:班级与学生的关系,在实体类中表示一对多关系

    <bean id="Student" class="spring.Students">

        <property name="name" value="Ninja"></property>
        <property name="age" value="19"></property>

        <property name="calsses">
            <!--内部bean-->
            <bean id="classes" class="spring.Classes">
                <property name="name" value="IT90班"/>
            </bean>
        </property>

    </bean>

5、注入属性-内部bean-级联值 

(1)方法一

与上方相同

(2)方法二

 <bean id="Student" class="spring.Students">
        <property name="name" value="Ninja"></property>
        <property name="age" value="19"></property>
        <property name="calsses" ref="classes"></property>
    </bean>
    <bean id="classes" class="spring.Classes">
        <property name="name" value="IT90班"></property>
    </bean>

6、注入属性-集合属性

constructor先执行 property后执行 后执行的会把前面的覆盖 构造方法传参

使用迭代器逐个去取list和map里面的每个值

ref引用  引用类型 里面的被创建一次 外面的就会被创建一次

(1)注入数组类型属性

 <property name="arrays">
        <array>
            <value>one</value>
            <value>two</value>
            <value>three</value>
        </array>
    </property>

(2)注入集合类型属性


<!--迭代器逐个去取list和map里面的每个值-->
    <property name="list">
      <list>
        <value>上单</value>
        <value>辅助</value>
        <value>打野</value>
        <value>下单</value>
      </list>
</property>

(3)注入Map类型属性

<property name="map">
        <map>
            <entry key="1" value="nm"></entry>
            <entry key="2" value="nm"></entry>
            <entry key="3" value="nm"></entry>
            <entry key="4" value="nm"></entry>
        </map>
</property>

(4)注入Set类型属性

 <property name="list">
    <set>
        <value>上单</value>
        <value>辅助</value>
        <value>打野</value>
        <value>下单</value>
    </set>
</property>

(5)集合里是对象属性

<property name="list">
    <list>
       <ref bean="对象"></ref>
       <ref bean="对象1"></ref>
    </list>
</property>

7、基于Xml自动装配属性

定义:根据指定装配规则,Spring将自动匹配的属性值进行注入

<!--对象注值 自动装配autowire  constructor 构造方法   byname bytype-->

<bean id="teacher" class="spring.Teacher" autowire="byType"></bean>

8、基于Xml方式—引入外部文件 

场景:spring配置JDBC数据连接文件的引入

创建Springw文件,引入context命名空间并且设置引入外部的配置文件


B.基于注解方式

1、什么是注解?

(1)代码里的特殊的标记  格式:@注解名称(属性名称=“属性值”)

(2)可以在类、方法、属性上添加注解

2、使用注解的目的?

(1)简化Xml配置,让程序变的优雅、简便

(2)打个比方:如果所有的bean创建都丢在Xml文件里,会使代码量变的非常庞大,繁琐,可读性差。

3、注解的运用

(1)创建对象提供的注解

1.@Componet:最普通的组件,可以注入到spring容器进行管理,用于标注一般类

2.@Service:作用服务层  服务器类的实现类

3.@Controller:作用于业务逻辑层 控制器类

4.@Repository:作用于持久层 数据访问层

(2)注入属性提供的注解

1.@Autowired(自动装配):
①、作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。
②、如果IOC容器中没有任何bean的类型和要注入的变量类型匹配,则报错。位置:
可以是变量上,也可以是方法上。
③、如果IOC容器中有多个类型匹配时, 对比变量名, 自动注入和当前变量名一样的IOC容器中的对象,如果没有则报错。

2.@Qualifier:
①、作用:在按照类中注入的基础之上, 再按照名称注入。
②、它在给类成员注入时不能单独使用。但是在给方法参数注入时可以。属性:value: 用于指定注入bean的id名称。可以配合Autowired

3.@Resource:
①、作用:直接按照bean的id注入。它可以独立使用, 相当于Autowired和Qualifier的结合。

②、属性:name:用于指定bean的id

③、注意:JDK8可以使用,JDK9不能使用

4.@Autowired和@Resource区别:

(1)@Autowired:自动按照类型type注入。
(2)@Resource:自动按照bean的id注入。可以独立使用,相当于Autowired和Qualifier的结合。


三、AOP

1、概念

面向切面编程。简单描述就是:将程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对自己的已有方法进行增强。无侵入式的不改变原有逻辑的情况下去增强添加逻辑,减少重复代码、提高开发效率、维护方便。

核心思想:在程序运行期间,在不修改源码的基础上对已有方法进行增强

什么是切面?

举个例子:要理解切面编程,就需要先理解什么是切面。首先确定西瓜的一个切入点,用刀把一个西瓜分成两瓣,切开的切口就是切面

2、AOP底层实现原理

使用动态代理技术:可以去看看我这篇比较详细 Java动态代理_CSDNzgcxy的博客-CSDN博客

(1)JDK实现动态代理(基于接口的动态代理)
(2)CGLIB实现动态代理(基于子类动态代理)

3、实践出真理

准备步骤:

(1)导入依赖

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.6</version>
    </dependency>

(2)创建一个SpringAOP的包

(3)创建一个Xml文件

<!--SpringAOP扫描此包下面的类-->
<context:component-scan base-package="SpringAOP"></context:component-scan>

首先来举个栗子:某一天你要出去买东西,你要买一瓶“红茶” 是不是得做相应的步骤 称作为“原有的代码” 创建一个类 BuyRedTea

@Component//向容器声明这是一个bean 让容器管理
public class BuyRedTea 
{
    public void down(){
        System.out.println("下楼..");
    }
    public void gotoMarket(){
        System.out.println("去超市..");
    }
    public void buyRedtea(){
        System.out.println("买红茶..");
        int n=0/1; //决定是否正常执行  改成1/0不正常执行
    }
    public void pay() {
        System.out.println("扫码付钱..");
    }
    public void up(){
        System.out.println("上楼..");
    }
}

 然后你在买红茶之前又买了“绿茶” ,但又不能修改上面的逻辑。就得使用一个“前置增强”。然后老板这时候又给你发了工资,你买完红茶绿茶后又想安排一包华子,称为”后置增强“。那么此时买红茶这件事就被称为“切入点”,同时也可以使用一个环绕增强,在前置和后置前后增强。当出现异常就会返回异常,当你买完红茶后发现资金未到账就会出现不正常执行。具体如下:

@org.aspectj.lang.annotation.Aspect//声明一个切面类,因为类名与注解名一致产生全路径
@EnableAspectJAutoProxy//开启切面类的自动代理
@Component//向容器声明是bean 让容器管理
public class Aspect
{
    //切入点的全路径
    @Pointcut("execution(public void BuyRedTea.buyRedtea())")//全路径有参数就加上一个*到括号中
    public void pointCat(){//用来绑定切入点的声明 用这个代替上面的方法
    }
    @Before("pointCat()")//前置增强  切入点之前执行的
    public void before(){
        System.out.println("买绿茶");
    }

    //切入点为buyRedtea买红茶的方法

    @After("pointCat()")//后置增强 切入点后执行
    public void after(){
        System.out.println("买华子..");
    }
    //正常执行和不正常执行都是后置方法
    @AfterReturning("pointCat()")//正常执行输出
    public void normal(){
    System.out.println("钱够"); 
    }
    @AfterThrowing("pointCat()")//不正常执行
    public  void w(){
    System.out.println("钱不够");
    }
    @Around("pointCat()")//环绕增强 
    public Object around(ProceedingJoinPoint joinPoint)
    {
    try {
        System.out.println("环绕前置");
        //@Before
        Object object=joinPoint.proceed();//调用byredtea
        //@AfterReturning/@AfterThrowing
        System.out.println("环绕后置");
        return object;
    } catch (Throwable throwable) {
        throwable.printStackTrace();
        System.out.println("环绕异常");
    }
    return null;
    }
}

然后创建一个测试类来看一下效果

public class Run 
{
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("Cig.xml");
        BuyRedTea buyredTea= (BuyRedTea) context.getBean("buyRedTea");//拿到这个类 调用这个方法
        buyredTea.down();
        buyredTea.gotoMarket();
        buyredTea.buyRedtea();
        buyredTea.pay();
        buyredTea.up();
    }
}

①、JoinPoint(连接点):指那些被拦截到的点。(在Spring中这些点指的是方法,因为Spring只支持方法类型的连接点)。
②、PointCut(切入点):指的是要对哪些JoinPoint进行拦截的定义。
③、Advice(通知/增强):指拦截到JoinPoint之后所要做的事情。

通知(Advice):实际增强的内容被称为通知

1.@Before: 前置通知, 在方法执行之前执行
2.@After: 后置通知, 在方法执行之后执行

返回通知和异常通知都属于后置增强,在后置增强前执行。
3.@AfterRunning: 返回通知, 在方法返回结果之后执行  正常执行返回
4.@AfterThrowing: 异常通知, 在方法抛出异常之后  不正常执行返回
5.@Around: 环绕通知, 围绕着增强方法执行

④、Target(目标对象):代理的目标对象。
⑤、Weaving(织入):指把增强应用到目标对象来创建新的代理对象的过程。
spring采用动态代理织入;
Aspect采用编译器织入和类装载期织入。
⑥、Aspect(切面):是切入点和通知的结合。

学习产生成果 成果改变生活 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值