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 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="" class=""></beans> </beans>
2.3 spring对bean的管理细节
2.3.1 创建bean的三种方式
1.使用默认构造函数创建,在spring配置文件配id和class属性的bean <bean id="" class=""></beans> 2.使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器) <bean id="aaa" class="com.factory.aaa"></beans> <bean id="bbb" factory-bean="aaa",factory=method=""getbbb></beans> 3.使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器) <bean id="aaa" class="com.factory.StaticFactory" factory-method="getaaa"></beans>
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对象 <bean id="" class=""> <constructor-arg ></constructor-arg> </beans> 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标签的<property> 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: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService" class="cn.zzz.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <bean id="accountDao" class="cn.zzz.dao.impl.AccountDaoImpl"> <property name="runner" ref="runner"></property> </bean> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"> <constructor-arg name="ds" ref="dataSource"></constructor-arg> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring01?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"></property> <property name="user" value="root"></property> <property name="password" value="1234"></property> </bean> </beans>
AccountServiceImpl:
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public List<Account> 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<Account> findAllAccount(); /* 根据id查找 */ Account findAccountById(Integer accountId); /* 保存 */ void saveAccount(Account account); /* 更新 */ void updateAccount(Account account); /* 删除 */ void deleteAccount(Integer accountId); }
AccountDao:
public interface AccountDao { /* 查询所有 */ List<Account> 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<Account> findAllAccount() { try { return runner.query("select *from account",new BeanListHandler<Account>(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>(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<Account> 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<Account> 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<Account> findAllAccount() { try { return runner.query("select *from account",new BeanListHandler<Account>(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>(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约束:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
四:spring中的事务管理
题外:使用jdbcTemplate时,可以在dao中继承JdbcDaoSupport,便可以省去定义和注入,使用时直接super.getJdbcTemplate().方法。
基于xml的事务管理:
bean.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="accountService" class="cn.zzz.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <bean id="accountDao" class="cn.zzz.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/spring01?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"></property> <property name="username" value="root"></property> <property name="password" value="lin990306"></property> </bean> <!-- spring中基于XML的声明式事务控制配置步骤 1、配置事务管理器 2、配置事务的通知 此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的 使用tx:advice标签配置事务通知 属性: id:给事务通知起一个唯一标识 transaction-manager:给事务通知提供一个事务管理器引用 3、配置AOP中的通用切入点表达式 4、建立事务通知和切入点表达式的对应关系 5、配置事务的属性 是在事务的通知tx:advice标签的内部 --> <!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置事务的通知--> <tx:advice id="txManager" transaction-manager="transactionManager"> <!-- 配置事务的属性 isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。 propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。 read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。 timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。 rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。 no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。 --> <tx:attributes> <tx:method name="*" read-only="false" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="SUPPORTS"/> </tx:attributes> </tx:advice> <!--配置aop--> <aop:config> <!--建立切入点表达式--> <aop:pointcut id="pt1" expression="execution(* cn.zzz.service.impl.*.*(..))"/> <!--建立切入点表达式和事务通知的对应关系 --> <aop:advisor advice-ref="txManager" pointcut-ref="pt1"></aop:advisor> </aop:config> </beans>
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<Account> 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<Account> 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容器环境下执行。
来源:https://www.cnblogs.com/codezzz/p/12283761.html