Spring

Spring

一、概述:

以下概述内容拷自w3cschool

Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。
Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。
Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。
Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。
Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。

两大重点:

1.依赖注入(DI)
Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。

依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。依赖注入是 Spring 框架的核心部分。

2.面向切面的程序设计(AOP):
Spring 框架的一个关键组件是面向切面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是切面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

Spring 框架的 AOP 模块提供了面向切面的程序设计实现,可以定义诸如方法拦截器和切入点等,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

二、Ioc:

2.1spring Ioc容器(控制反转):

作用:减小类/程序间的耦合

个人理解:运行时,找对象的事变成了间接寻找。没有使用ioc时,是直接寻找,找不到,编译便报错,而使用后,spring会创建一个工厂,寻找的事交给了工厂来处理,由工厂来寻找所需要的类,这样便减少了类与类之间的耦合,进一步实现低耦合高内聚!但Ioc只能做到减小,无法做到真正的解耦。

2.2 两大容器:

2.2.1:BeanFactory 容器和 ApplicationContext 容器(常用):

BeanFactory 可以理解为含有bean集合的工厂类。而 ApplicationContext 是他的一个子接口(进行了扩展)。

BeanFactory 是一个基本的容器,他无法支持aop、web等功能。

BeanFactory 能做到的事, ApplicationContext 都能做到。

ApplicationContext: 单例对象适用 采用此接口

它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。

BeanFactory: 多例对象使用

它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。

2.2.2 ApplicationContext的三个常用实现类:

ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)

FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)

AnnotationConfigApplicationContext: 读取注解创建容器

相关代码:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
xxx x = (xxx)ac.getBean("xxx"); //要强转类型
xxx x = ac.getBean("xxx",xxx.class);

bean.xml


2.3 spring对bean的管理细节

2.3.1 创建bean的三种方式

1.使用默认构造函数创建,在spring配置文件配id和class属性的bean

2.使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

<bean id="bbb" factory-bean="aaa",factory=method=""getbbb>

3.使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

2.3.2 bean对象的作用范围

scope属性:
*singleton 单例(默认)
*prototype 多例
*request web应用的请求范围
*session web应用的会话范围
*global-session: 作用于集群环境的会话范围

2.3.3 bean对象的生命周期

单例对象

出生:容器创建时

活着:容器在便在

死亡:容器销毁,死亡

多例对象

出生:当我们使用spring框架为我们创建(同beanFactory)

活着:对象在使用,就活着

死亡:等着java垃圾回收机制回收

2.4 依赖注入(DI)

1.能注入的数据:
1.基本类型和String
2.其他bean类型
3.复杂类型/集合类型

2.注入方式:
1.使用构造函数注入
使用的标签:constructor-arg
标签内的属性:
type:指定注入的数据的数据类型,也是构造函数中某个或某些参数的类型
index:用于指定注入的数据给构造函数中指定索引位置赋值
name:用于指定给构造函数中指定名称的参数赋值
value:提供基本类型和String类型的数据
ref:指定其他的bean类型数据,即在Ioc核心容器中出现过的bean对象


2.使用set注入(常用)
标签:property
标签内属性:
name:注入时所调用的set方法名称
ref:指定其他的bean类型数据,即在Ioc核心容器中出现过的bean对象

使用注解注入

2.5注解:

在bean.xml中要先表明扫描的包(要加新的约束)

<context:component-scan base-package="xxx"></context:component-scan>

创建对象:

Component:将当前类对象存入spring容器,有个value属性:相当于bean的id(默认为当前类名第一个字母小写)
以下三个与上面作用一模一样
Controller:一般用于表现层
Service:一般用于业务层
Repository:一般用于持久层

注入数据:

作用同bean标签的
1.Autowired:按照类型自动注入,此时set方法不为必须的了
注入时,没有匹配类型则报错,如果多个匹配的类型,则以id来匹配
2.Qualifier:按照类中注入的基础之上再按照名称注入,注入类成员不能单独食用,给 方法参数可以,属性value:用于指定注入bean的id。
3.Resource:直接按照bean的id注入
以上3个只能注入其他bean类型,基本类型和String不能,另外,集合类型只能通过xml实现

4.Value:用于注入基本类型和String

指定作用范围:

Scope:
*singleton 单例
*prototype 多例

配置类注解:

作用同bean.xml
1.Congifuration:表面当前类是一个配置类
2.ComponentScan:通过注解表明spring创建容器时要扫描的包
3.Bean:用于把当前方法的返回值作为bean对象存入springIoc容器,属性name:指定bean的id,默认方法名称
4.Import(): 用于插入其他配置类
5.PropertySource: 扫描的配置文件(一般是jdbc.properties)
6.@EnableTransactionManagement:开启事务支持

2.6案例:

xml配置案例:

bean.xml:













AccountServiceImpl:

public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;

public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

public List findAllAccount() {
return accountDao.findAllAccount();
}

public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}

public void saveAccount(Account account) {
accountDao.saveAccount(account);
}

public void updateAccount(Account account) {
accountDao.updateAccount(account);
}

public void deleteAccount(Integer accountId) {
accountDao.deleteAccount(accountId);
}
}

AccountService:

public interface AccountService {

/*
查询所有
*/
List findAllAccount();

/*
根据id查找
*/
Account findAccountById(Integer accountId);

/*
保存
*/
void saveAccount(Account account);

/*
更新
*/
void updateAccount(Account account);

/*
删除
*/
void deleteAccount(Integer accountId);
}

AccountDao:

public interface AccountDao {
/*
查询所有
*/
List findAllAccount();

/*
根据id查找
*/
Account findAccountById(Integer accountId);

/*
保存
*/
void saveAccount(Account account);

/*
更新
*/
void updateAccount(Account account);

/*
删除
*/
void deleteAccount(Integer accountId);
}

AccountDaoImpl:

public class AccountDaoImpl implements AccountDao {
private QueryRunner runner;

public void setRunner(QueryRunner runner) {
this.runner = runner;
}

public List findAllAccount() {
try {
return runner.query("select *from account",new BeanListHandler(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}

public Account findAccountById(Integer accountId) {
try {
return runner.query("select *from account where id = ?",new BeanHandler(Account.class),accountId);
}catch (Exception e){
throw new RuntimeException(e);
}
}

public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money) value (?,?)",
account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}

public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",
account.getName(),account.getMoney(),account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}

public void deleteAccount(Integer accountId) {
try {
runner.update("delete from account where id = ?",
accountId);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}

Test:

public class TestCurd {
@Test
public void TestFindAll() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as = ac.getBean("accountService",AccountService.class);
List accounts = as.findAllAccount();
for (Account account : accounts) {
System.out.println(account);
}
}

@Test
public void TestFindOne() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as = ac.getBean("accountService",AccountService.class);
Account account = as.findAccountById(1);
System.out.println(account);
}

@Test
public void TestSaveAccount() {
Account account = new Account();

account.setName("老王");
account.setMoney(1234f);

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as = ac.getBean("accountService",AccountService.class);

as.saveAccount(account);
}

@Test
public void TestUpdateAccount() {
Account account = new Account();
account.setId(1);
account.setName("AAA");
account.setMoney(1234f);
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as = ac.getBean("accountService",AccountService.class);
as.updateAccount(account);
}

@Test
public void TestDeleteAccount() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as = ac.getBean("accountService",AccountService.class);

as.deleteAccount(4);
}
}

注解配置:

SpringConfiguration:

/**
* 相当于bean.xml
*/

@Configuration //表明他是一个配置类,会被被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
@ComponentScan("cn.zzz") //表面创建容器扫描的包
public class SpringConfiguration {

@Bean("runner")
@Scope("prototype")
public QueryRunner runner(DataSource dataSource) {
return new QueryRunner(dataSource);
}

@Bean("dataSource")
public DataSource creatDatasource() {
ComboPooledDataSource cbp = new ComboPooledDataSource();
try {
cbp.setDriverClass("com.mysql.cj.jdbc.Driver");
cbp.setJdbcUrl("jdbc:mysql://localhost:3306/spring01?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC");
cbp.setUser("root");
cbp.setPassword("lin990306");
return cbp;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

AccountServiceImpl:

@Service("accountService")
public class AccountServiceImpl implements AccountService {

@Autowired
private AccountDao accountDao;

public List findAllAccount() {
return accountDao.findAllAccount();
}

public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}

public void saveAccount(Account account) {
accountDao.saveAccount(account);
}

public void updateAccount(Account account) {
accountDao.updateAccount(account);
}

public void deleteAccount(Integer accountId) {
accountDao.deleteAccount(accountId);
}
}

AccountDaoImpl:

@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {

@Autowired
private QueryRunner runner;

public List findAllAccount() {
try {
return runner.query("select *from account",new BeanListHandler(Account.class));
}catch (Exception e){
throw new RuntimeException(e);
}
}

public Account findAccountById(Integer accountId) {
try {
return runner.query("select *from account where id = ?",new BeanHandler(Account.class),accountId);
}catch (Exception e){
throw new RuntimeException(e);
}
}

public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money) value (?,?)",
account.getName(),account.getMoney());
}catch (Exception e){
throw new RuntimeException(e);
}
}

public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",
account.getName(),account.getMoney(),account.getId());
}catch (Exception e){
throw new RuntimeException(e);
}
}

public void deleteAccount(Integer accountId) {
try {
runner.update("delete from account where id = ?",
accountId);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}

其他与xml配置案例一样

三、Aop

AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。

相关术语:

Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的 连接点。

Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。

Advice(通知/增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方 法或 Field。

Target(目标对象): 代理的目标对象。

Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect(切面): 是切入点和通知(引介)的结合

xml约束:




org.aspectj
aspectjweaver
1.8.7

四:spring中的事务管理

题外:使用jdbcTemplate时,可以在dao中继承JdbcDaoSupport,便可以省去定义和注入,使用时直接super.getJdbcTemplate().方法。

基于xml的事务管理:
bean.xml:
















<tx:advice id="txManager" transaction-manager="transactionManager">

tx:attributes
<tx:method name="" read-only="false" propagation="REQUIRED"/>
<tx:method name="find
" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>


aop:config

<aop:pointcut id="pt1" expression="execution(* cn.zzz.service.impl..(..))"/>

<aop:advisor advice-ref="txManager" pointcut-ref="pt1"></aop:advisor>
</aop:config>

AccountServiceImpl:

public class AccountServiceImpl implements AccountService {

private AccoundDao accountDao;

public void setAccountDao(AccoundDao accoundDao) {
this.accountDao = accoundDao;
}

public Account findAccoundByName(String AccountName) {
return accountDao.findAccoundByName(AccountName);
}

public void updateAccount(Account account) {
accountDao.updateAccount(account);
}

public List findAll() {
return accountDao.findAll();
}

public void transfer(String outName, String inName, Float money) {
Account outAccount = accountDao.findAccoundByName(outName);
Account inAccount = accountDao.findAccoundByName(inName);

outAccount.setMoney(outAccount.getMoney()-money);
inAccount.setMoney(inAccount.getMoney()+money);

accountDao.updateAccount(outAccount);

// int i =1/0;
accountDao.updateAccount(inAccount);
}
}

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {

@Autowired
private AccountService as;

@Test
public void TestFindAll(){
List accounts = as.findAll();
for (Account account : accounts) {
System.out.println(account);
}
}

@Test
public void TestFindAccountByName(){

Account account = as.findAccoundByName("AAA");
System.out.println(account);
}

@Test
public void TestTransfer(){

as.transfer("AAA","bbb",100f);
}
}

这种单元测试写法是为了让测试在Spring容器环境下执行。

posted @ 2020-02-08 16:13  lopzzzzzzzzzzzzzz  阅读(229)  评论(0)    收藏  举报