写点什么

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

发布于: 5 小时前

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


IOC 创建对象的两种方式


  1. 无参构造方式


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


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

2 有参构造方式


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

修改 bean.xml 方法


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


spring 配置


1 别名配置


spring 别名的配置规则


<alias name="hello" alias="helloOne"/>


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

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


2 bean 配置

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


Hello hello = new Hello();


hello.setName(Spring);


3 多团队协作 import


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


<import resource="{path}/beans.xml"/>


依赖注入


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


1 有参构造器注入


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

2 set 注入


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


创建实体类用于测试


Student.java


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


Address.java

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

对象注入

在这里 ref 是引用。


数组注入

list 注入

map 注入

set 注入

property

null 注入

结果

3 使用命名空间注入


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

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

4 Bean 的作用域

Singleton 单例


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


<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">


Prototype


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


<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>


Request


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


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


Session


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


<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>


Bean 的装配与管理


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


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


1 通过 ref 来装配


我们现在有三个类


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


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


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

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


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


2 xml 配置实现自动配置


2.1 byName

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


2.2 byType

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


3 使用注解实现自动装配


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


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


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


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


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


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


开启属性注解支持!


context:annotation-config/


3.1 Autowired


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


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


使用方法:


实体类:

bean.xml

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


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


3.2 @Qualifier


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


@Qualififier 不能单独使用。


使用方法:


实体类:

bean.xml

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


它也可以写在 set 方法上。


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


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


4.1 @Resource


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


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


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


实体类:

bean.xml

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


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


5 @Autowired 与 @Resourse 的异同


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


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


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


注解开发


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


1 准备工作


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


前置环境:

2 bean 注入和属性值赋值


实体类:

可以在属性值上直接注入,但是有 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。

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


注解方式,快捷而优雅


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


5 作用域 @scope


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


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

6 小结


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


xml 方式

注解方式

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


例如:


private SqlService sqlService = new MySqlServiceImpl()


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


private SqlService sqlService = new OracleServiceImpl()


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

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


代理模式


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


代理模式分为:


静态代理


动态代理


用 UML 图来简单描述一下

1 静态代理


静态代理角色分析


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


真实角色 : 被代理的角色


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


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


静态代理实例一:


抽象角色 Rent

真实角色 Host

客户 client

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


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


静态代理实例二:

抽象接口 UserService


真实角色 UserServiceImpl

代理角色 UserServiceImplProxy


客户端

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


这也是 AOP 底层的实现机制


2 动态代理


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


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


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


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


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


基于类的动态代理–cglib


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


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


核心 : InvocationHandler 和 Proxy 。

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


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


使用方法:

3 小结


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


AOP


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


1 Aop 在 Spring 中的作用


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


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


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


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


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


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


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


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

2 AOP 的使用


环境:需要导入 jar 包

第一种方式


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


抽象接口 UserService

真实角色(房东)

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


第二种方式


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


自定义的代理类 Proxy

第三种方式


通过注解的方式实现

bean.xml

整合 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

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

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


优化


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

将 sqlsession 获取进一步简化。


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


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

将 sqlSessionFactory 注入即可。

将 UserMapperImpl 分离成 service 层


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


注入 session 类型

继承 SqlSessionDaoSupport 类

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


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


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


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


使用方法:


配置文件:


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

调用


private UserMapper userMapper;


直接调用即可使用。


事务


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


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


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


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


事务四个属性 ACID


1.原子性(atomicity)


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


2.一致性(consistency)


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


3.隔离性(isolation)


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


4.持久性(durability)


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


事务的作用


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


事务的使用


引入 aop 和 tx 头文件

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


详细配置事务的通知规则

使用 aop 织入

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

用户头像

还未添加个人签名 2021.04.20 加入

Java工具与相关资料获取等WX: pfx950924(备注来源)

评论

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