厉害了!10年架构师整理的Spring中升华代码的技巧,让你爱不释手

284 阅读15分钟

今日分享开始啦,请大家多多指教~

IOC创建对象的两种方式

1. 无参构造方式

sprirng使用无参构造的方式新建对象,然后使用set方法注入属性,表现为在bean.xml的property来对属性进行赋值。

如果实体类中没有set方法,property来对属性进行赋值。

image.png

2 有参构造方式

在实体类增加有参构造方法,(无参构造是默认含有的。)

image.png

修改bean.xml方法

image.png

回顾一下java的知识,在创建java对象时,无参构造函数是默认含有的,但是有参构造函数写了之后,默认的无参构造就会失效,这个时候要使用无参构造需要手动写一个无参构造函数。

spring配置

1 别名配置

spring别名的配置规则

和mybatis的有些类似,在mybatis中是这样使用的。

image.png

配置了别名之后,在java代码中就可以通过别名来获取对象实例了。

2 bean配置

image.png

这一个配置文件用java代码来解释就是

Hello hello = new Hello();

hello.setName(Spring);

3 多团队协作import

如果在团队开发中要使用别人写的xml文件,可以使用import的方式来实现,这样,就可以在自己的bean中使用别人bean的属性。

依赖注入

依赖注入作为Spring实现IOC的方式,允许大家使用多种方式来进行bean属性值的注入。

1 有参构造器注入

在4当中已经实现了构造器注入

image.png

2 set注入

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型, 没有set方法 , 是 is .

创建实体类用于测试

Student.java

image.png

因为学生对象中含有对象Address

Address.java

常量注入(常用的数据类型,如inter,string,double等)

image.png

对象注入

image.png

在这里ref是引用。

数组注入

image.png

list注入

image.png

map注入

image.png

set注入

image.png

property

image.png

null注入

image.png

结果

image.png

3 使用命名空间注入

P命名空间注入 : 需要在头文件中假如约束文件

image.png

c 命名空间注入 : 需要在头文件中假如约束文件

image.png

4 Bean的作用域

image.png

Singleton单例

Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。

Prototype

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求时都会创建一个新的bean实例。

Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。

<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。

Bean的装配与管理

在很多情况下,我们需要在一个类中使用另一个类对象,但是我们已经将对象的创建交给了Spring管理。

所以我们需要通过一些方式来对我们的类中的对象属性进行装配,也就是对象注入,其原理方式和属性值的注入类似。

1 通过ref来装配

我们现在有三个类

我们必须将三个类注入到SpringIOC容器中。

并将Cat和Dog装配到Peoson中才可以正常使用,就和属性值的注入类似。

实质就是将Cat和Dog实例从IOC中取出并赋值给Peoson类。

image.png

这样手动装配也很方便,但是又更加简便的方式来简化这一过程–>自动装配autowire。

我们可以使用xml配置 , 或者注解的方式来实现自动装配。

2 xml配置实现自动配置

2.1 byName

image.png

只需要通过这种简单的自动装配方式就可以实现之前的功能。它是根据bean的id来和set方法属性名来自动进行匹配的。

2.2 byType

image.png

用法一样,这个是通过类的类型来自动装配。因为是通过类型,所以同一类型的对象实例只能同时存在一个。

3 使用注解实现自动装配

jdk1.5开始支持注解,spring2.5开始全面支持注解。

第一步我们使用ref引用的方式来bean实例装配。

第二步我们使用autowire的方式来实现bean自动装配。

第三步将用注解的方式来实现自动装配。

使用注解方式需要增加一些配置。

在spring配置文件中引入context头文件。

开启属性注解支持!

context:annotation-config/

3.1 Autowired

@Autowired是按类型自动转配的,不支持id匹配。

需要导入 spring-aop的包!(已经在mvc的jar包中导入)

使用方法:

实体类:

image.png

bean.xml

image.png

@Autowired默认是通过类型来匹配的,可以理解为byType的匹配规则

因为注解方式不是使用set的方法来进行注入,所以在实体类中可以不写set方法。

3.2 @Qualifier

@Autowired是根据类型自动装配的,加上@Qualififier则可以根据byName的方式自动装配

@Qualififier不能单独使用。

使用方法:

实体类:

image.png

bean.xml

image.png

通过这么一种方式,就可以实现和ref一样的功能。

它也可以写在set方法上。

@Autowired(required = false) //这个注解意思是允许参数为空,但是我测试默认他就允许为空,不知道它的意义在哪。

4 使用另一种注解的方式来实现自动配置

4.1 @Resource

@Resource如有指定的name属性,先按该属性进行byName方式查找装配;

其次再进行默认的byName方式进行装配;

如果以上都不成功,则按byType的方式自动装配。

实体类:

image.png

bean.xml

image.png

通过这样的方式,也可以实现ref的功能。

它和**@Autowired一样可以写在set方法**上。

5 @Autowired与@Resourse的异同

同样可以写在属性或者set方法上,配合属性使用可以实现ref的功能。

@Autowired属于spring规范,默认byType的方式匹配

@Resource(属于J2EE复返),默认通过byname的方式匹配。

注解开发

在spring中,虽然可以使用xml的方式来进行bean的注入,bean的装配,bean属性值的注入。但是实际开发用注解进行开发是真的香,而使用xml进行bean的管理和装配的方式将会逐渐摒弃。

1 准备工作

在完成通过注解的方式来对bean进行注入之后,也可以用注解的方式来实现属性的自动注入。

前置环境:

image.png

2 bean注入和属性值赋值

实体类:

image.png

可以在属性值上直接注入,但是有set方法时建议在set方法上注入。

通过@Value("")的方式直接注入属性值,功能和bean中的相同。

@Component注解和bean.xml文件中的bean标签作用一样,意思是将这个类交由spring容器管理。

通过这种方式将实体类注入IOC容器之后不再需要在bean.xml中对实体类进行注入。

3 Component衍生注解

我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!

@Component三个衍生注解

为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

**@Controller:**web层

**@Service:**service层

**@Repository:**dao层

写上这些注解,就相当于将这个类交给Spring管理装配了!

4 bean的自动装配

在之前的博客有写到在一个bean中使用另一个bean。

image.png

而通过这么一种方式,实现了bean的装配。结合之前的内容,我们将可以完全摒弃xml配置文件的方式来对bean进行管理和注入。

注解方式,快捷而优雅

这样配合使用就完成了所有在bean.xml中的类和属性注入的所有功能。

5 作用域 @scope

singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收。

image.png

6 小结

使用全注解的方式是主流的一种只用方式,在后续的springboo中更是常见使用。但是了解xml的方式有助于我们使用和理解框架的逐步演进。

xml方式

image.png

注解方式

image.png

依赖注入只是IOC的一种实现,我们希望将对象的创建和管理交给Spring容器管理,这会让我们在管理类的时候不再需要进行复杂的代码更改,而用注入的方式一次性改变

例如:

private SqlService sqlService = new MySqlServiceImpl()

如果我们需要更改实现类,我们需要重新new一个对象

private SqlService sqlService = new OracleServiceImpl()

但是依赖注入的方式不同,它是这样实现的

image.png

这样节省了我们出创建一个新对象的额外开销。

代理模式

AOP面向切面编程的底层思想就是代理模式,理解代理模式对理解AOP模式很有帮助。

代理模式分为:

静态代理

动态代理

用UML图来简单描述一下

image.png

1 静态代理

静态代理角色分析

抽象角色 : 一般使用接口或者抽象类来实现

真实角色 : 被代理的角色

代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .

客户 : 使用代理角色来进行一些操作 .

静态代理实例一:

抽象角色Rent

image.png

真实角色Host

image.png

客户client

image.png

**理解:**代理模式中,真实角色和代理角色共同实现租房这一抽象接口,真正拥有租房权限的是真实角色,因为代理角色找到了真实角色,真实角色将租房这一权限给代理。

**优点:**代理角色除了代理了租房这一功能还可以提供其他的一些附加功能,比如签合同,看房等,这是真实角色不想做的事情,但是却不会影响他本身的租房功能。

静态代理实例二:

抽象接口UserService

image.png

真实角色UserServiceImpl

image.png

代理角色UserServiceImplProxy

客户端

image.png

**理解:**和之前的静态代理案例一一样,通过代理角色的方式,在实现真实角色功能的基础上,不影响地增加一些代理功能。

这也是AOP底层的实现机制

2 动态代理

就和在mybatis时做分页一样,当分页的类型多的时候,我们不希望为每一种类型都增加一个分页类,这个时候我们使用泛型的方式来实现不同类型数据的返回匹配。

动态代理的角色和静态代理的一样 .

动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的

动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理

基于接口的动态代理----JDK动态代理

基于类的动态代理–cglib

现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist

JDK的动态代理需要了解两个类

核心 : InvocationHandler 和 Proxy 。

image.png

通过这样的方式,我们就可以动态的代理Rent这一类的对象了。

除了代理这一类的方法,有时候我们希望能够实现所有对象的代理,这个时候我们可以把Rent改为Object类型,这样就可以代理所有的对象类型了。

使用方法:

image.png

3 小结

就和工具类一样,动态代理可以很方便的动态完成一些有需求变更和频繁使用的工作。

AOP

AOP作为spring的两大核心之一,即面向切面编程,它的底层实现是代理模式,横向的方式来对现有的功能进行加强,使业务逻辑和功能代码更好的脱耦合。

1 Aop在Spring中的作用

横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …

切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。

通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。

目标(Target):被通知对象。

代理(Proxy):向目标对象应用通知之后创建的对象。

切入点(PointCut):切面通知 执行的 “地点”的定义。

连接点(JointPoint):与切入点匹配的执行点。

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

image.png

2 AOP的使用

环境:需要导入jar包

image.png

第一种方式

通过继承已有的方法,然后通过AOP配置文件来设置切入面和执行环绕的方式

抽象接口UserService

image.png

真实角色(房东)

image.png

通过这样的一个方式,我们实现了之前和动态代理类似的功能。

第二种方式

有的时候它提供的代理方法可能不是很适配我们的功能需求,我们希望通过自定义代理类的方式来实现代理功能,而不是通过它现有的方法。

自定义的代理类Proxy

image.png

第三种方式

通过注解的方式实现

image.png

bean.xml

image.png

整合mybatis

mybatis实现对数据库操作的高效管理,而spring用一种新的方式实现对对象的创建和使用。

整合mybatis就是将mybatis的数据操纵和spring的控制反转结合起来。

导入相关jar包

改造mybatis

原本我们的mybatis是有User实体类和UserMapper接口和UserMapper.xml,还有mybatis-config.xml。

主要就是改造mybatis-config文件,我们需要把一些mybatis连接数据库的操作转移到spring中一起操作。

新建一个spring-config.xml文件

在这个文件中,我们将Sqlsession的获取,对数据库的连接,对mybatis的一些配置整合在了一起。

操作sqlsession

在测试类中用getbean()方式来获取session

image.png

通过一个UserMapperImpl实现类将session注入。(规范)

image.png

官方文档的规范是使用第二种方式来进行实现的,同时这也更符合spring依赖注入的思想。

优化

通过导入的方式将配置部分和普通的bean注入分离

image.png

将sqlsession获取进一步简化。

mybatis-spring1.2.3版以上才可以使用 .

继承SqlSessionDaoSupport, 直接利用 getSqlSession() 获得Sqlsession , 在bean管理就直接为UserMapperIml注入SqlSessionFactory(原来是注入sqlSession) 。

image.png

将sqlSessionFactory注入即可。

image.png

将UserMapperImpl分离成service层

有一个UserMapper.xml后再实现一个UserMapperImpl的话逻辑会有些乱,可以将UserMapperImpl分离出来,单独建一个service层。将session的获取在这一个层次进行。

注入session类型

image.png

继承SqlSessionDaoSupport类

image.png

获取sesission的方式进一步简化:

当我们的获取Session的操作更多的时候,我们希望以一种更加高效和更加便于管理的方式去获取session。

spring框架提供了一个自动扫描MapperScannerConfigurer的操作,它可以通过设置这个类的属性和自动扫描指定包来自动的将我们的session注入到包名下的所有mapper中。

我们可以直接获取mapper去操作,而将session的获取交给spring封装。

使用方法:

配置文件:

它需要手动地设置两个属性来为指定包名注入session.

image.png

调用

private UserMapper userMapper;

直接调用即可使用。

事务

对于事务的更详细地解释在我的另一篇博客中有显示

事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!

事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。

事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。

事务四个属性ACID

1.原子性(atomicity)

事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用。

2.一致性(consistency)

一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中。

3.隔离性(isolation)

可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

4.持久性(durability)

事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中。

事务的作用

当我们在操纵数据时,我们在同一个方法执行增删改查操作,我们希望当我们一个操作发生错误时,这个方法内的所有操作都失效。而spring的提供的很好的这个管理功能,叫做事务管理。

事务的使用

引入aop和tx头文件

image.png

定义为一个事务管理器,为它绑定数据源

详细配置事务的通知规则

image.png

使用aop织入

image.png

今日份分享已结束,请大家多多包涵和指点!