一、spring概述
- spring是轻量级的开源的javaEE框架。
- spring可以解决企业应用开发的复杂性
- spring有两个核心部分:IOC和AOP
- 1)IOC:控制反转,把创建对象过程交过Spring进行管理
- 2)AOP:面向切面,不修改源代码进行功能增强
- Spring特点:
1)方便解耦,简化开发
2)AOP编程支持
3)方便程序的测试
4)可以方便和其他框架组合
5)方便进行事物的操作
6)降低了API
准备工作
1、进入官网下载spring包
2、打开idea,创建普通java工程
3、导入Spring5相关的jar包
二、 IOC容器
1)ioc底层原理
什么是IOC
1、也叫控制反转,把对象创建和对象之间的调用过程,交过Spring
2、使用IOC目的:为了耦合度降低
ioc底层原理
1)xml解析、工厂模式、反射
2)IOC接口
IOC接口
1、ioc思想基于ioc容器完成,ioc容器底层就是对象工厂
2、Spring提供了ioc容器实现的两种方式(两个接口)
------1)BeanFactory:IOC容器基本实现方式,是Spring内部使用接口,一般不使用. 加载配置文件不会创建对象,在获取对象是才创建对象
-------2)ApplicationContext:BeanFactory接口的子接口,提供更加强大的功能,加载配置文件时就会把配置文件给创建
ApplicationContext接口的实现类
区别:filesystem…它的参数是文件的全路径
classpath…通过它的xml文件名
3)IOC操作Bean管理(基于xml)
什么是Bean管理
1)Bean管理指的是俩个操作
1)Spring 创建对象(类似于new 对象名)
2)Spring注入属性(类似于给属性赋值)
Bea管理操作的两种方式
1)基于xml配置文件方式创建
2)基于注解方式实现
创建对象
1)在spring的配置文件中使用bean标签,标签里面添加对应的属性,就可以实现对象的创建
<bean id="user1" class="com.qsh.User"></bean>
/**
id属性:唯一标识
class属性:你要创建类的全路径
**/
用Sprin配置文件创建对象时,默认也是执行无参数构造器
xml方式注入属性:
1)第一种注入方式:使用set方式注入
------创建属性和对的set方法
public class Book {
private String name;
private String bauthor;
public void setName(String name) {
this.name = name;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
}
-------用在配置文件中配置对象创建,配置属性注入
<!--配置User对象-->
<bean id="user2" class="com.bean1.Book">
<!--使用property完成属性注入
name:类的属性名称
value:属性注入的值
-->
<property name="name" value="九阴真经"></property>
<property name="bauthor" value="qinshenghang"></property>
</bean>
2)第二种注入方式:使用有参数构造进行注入
----------创建类,定义属性,创建属性对应有参数构造方法
public class Order {
private String name;
private String address;
public Order(String name, String address) {
this.name = name;
this.address = address;
}
}
--------用在配置文件中配置对象创建,配置构造函数的注入
<bean id="orders" class="com.bean1.Order">
<!--使用constructor完成属性注入
name:类的属性名称
value:属性注入的值
-->
<constructor-arg name="name" value="电脑" ></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
</bean>
IOC操作Bean管理(xml注入其他类型属性)
1、字面量
--------1)null设置属性值为null <property name="number" > <null/> </property>
--------2)属性值包含特殊符号
属性值包含特殊的符号 1.把<>进行转义 2.把带特殊符号类容写道CDATA中 <property name="address"> <value> <![CDATA[<南京>>]]> </value> </property>
注入对象类型的属性
1)外部bean
------创建Service类和dao类
------在Service中调用dao类里面的方法
-------在配置文件中进行配置
2)内部bean和级联赋值
--------一对多关系
---------在实体类之间表示一对多关系
---------在spring配置文件中进行配置
> 1)外部bean
//Service类中调用UerDaoIpl方法(原始方法)
UserDao user= new UerseDaoIpl();
user.update();
//Service实现类
public class UserService {
//创建UserDao类型的属性,生成set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("serverice adddd--");
}
}
//接口
public interface UserDao {
public void update();
}
//接口实现类
public class UerseDaoIpl implements UserDao {
@Override
public void update() {
System.out.println("dao UODATE------");
}
}
xml配置文件:
<!--配置Service和dao对象-->
<bean id="userdaopl" class="dao.UerseDaoIpl"></bean>
<bean id="userservice" class="service.UserService">
<!--
ref属性:UerDao对象bean标签的id值(把外部的bea注入进来)
-->
<property name="userDao" ref="userdaopl"></property>
</bean>
2)内部bean和级联赋值
//部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
//员工类
public class Emp {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
xml配置文件
<bean id="emp" class="bean.Emp">
<property name="ename" value="覃圣航"></property>
<property name="gender" value="男"></property>
<!--设置对象类型属性-->
<property name="dept">
<!--内部bean-->
<bean id="Dept" class="bean.Dept" >
<property name="dname" value="保安部"></property>
</bean>
</property>
</bean>
IOC操作Bean管理(xml注入集合list,map.set属性)
-------创建类,定义数组、list、map、set类型的属性,生成对应的set方法
-------在Spring配置文件中进行配置
<bean id="Stu" class="com.Spring.Stu">
<property name="courses">
<!--数组的的注入-->
<array>
<value>sad</value>
<value>123</value>
</array>
</property>
<property name="list">
<list>
<value>sad</value>
</list>
</property>
<property name="set">
<set>
<value>123</value>
</set>
</property>
<property name="map">
<map>
<entry key="姓名" value="覃圣航"></entry>
<entry key="年龄" value="19"></entry>
</map>
</property>
</bean>
</beans>
在集合里面设置对象类型的值
<!--注入list集合,但值是对象 -->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<!--创建多个course对象-->
<bean id="course1" class="com.Spring.Course">
<property name="aname" value="Spring5框架"></property>
</bean>
<bean id="course2" class="com.Spring.Course">
<property name="aname" value="mybatis框架"></property>
</bean>
把集合注入部分提取出来
1)在spring配置文件中引入名称空间util
xmlns:util="http://www.springframework.org/schema/util"
在xsi:schemaLocation后面加上 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-beans.xsd
2)提取list集合类型属性注入
<util:list id="books">
<value>123456</value>
<value>456789</value>
<value>456789</value>
</util:list>
3)提取list集合类型属性注入使用
<bean id="Book" class="com.Spring.Book">
<property name="name" ref="books"></property>
</bean>
5)IOC操作Bean管理(FactorBean)
Spring有两种bean,一种是普通bean,另外一种是工厂bean(FactoryBean)。
-----普通bean:在配置文件中定义bean类型就是返回类型
-----工厂bean:在配置文件中定义bean类型可以和返回的类型不一样。
1)创建类,让这个类作为工厂bean,实现FacroyBean接口
2)实现接口里面的方法,在实现的方法中定义返回bean类型
public class MyBean implements FactoryBean<Book> {
//定义bean返回的类型
@Override
public Book getObject() throws Exception {
return null;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
bean管理的作用域
-----作用域:在Spring中,设置创建的bean是单实例,还是多实列。
-------在Spring里面,默认情况下,bea是一个单实例对象
-------在spring配置文件bean标签里面有属性(sope)用于设置单实例还是多实例.
--------scope属性值:
1 ) 默认值,singleton表示是单实例对象
2 )prototype表示是多实例对象
//创建多实例对象
<bean id="Book" class="com.Spring.Book" scope="prototype">
<property name="name" ref="books"></property>
</bean>
bean管理的生命周期
--------什么周期:从对象创建到对象销毁的过程;
--------bean的生命周期:
1)通过构造器创建bea实例(无参构造器,有参构造器)
2)为bean的属性设置值和对其他bea的引用(调用set方法)
3)把bean实例传递bean后置处理器的方法(创建类实现接口BeanPostProcessor)
4)调用bean的初始化方法(需要配置初始化的方法)
5)把bean实例传递bean后置处理器的方法
6)bean可以使用了(对象获取到了)
7)当容器关闭时候,调用bean的销毁的方法(需要配置销毁的方法)
public class bean {
private String aname;
public bean() {
System.out.println("执行了第一步,通过构造器创建方法");
}
public void setAname(String aname) {
this.aname = aname;
System.out.println("执行了第二步,调用set属性");
}
public void csh(){
System.out.println("执行了第三步,初始化");
}
public void Destoy(){
System.out.println("执行了第五步,销毁");
}
@Test
public void test(){
ApplicationContext context=new ClassPathXmlApplicationContext("beanxml.xml");
bean bean1=context.getBean("bean",bean.class);
System.out.println("执行了第4步,对象获取到了");
//手动销毁
((ClassPathXmlApplicationContext)context).close();
}
}
//后配处理器
public class last implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后执行的方法");
return bean;
}
}
<!--init-method:代表初始化方法
destroy-method:代表销毁方法-->
<bean id="bean" class="Bean.bean" init-method="csh" destroy-method="Destoy">
<property name="aname" value="覃圣航"></property>
</bean>
<!--配置后配处理器-->
<bean id="last" class="Bean.last"></bean>
自动装配
----自动装配:根据指定装配规则(属性名称或者属性类型),Spring自动将配置的属性值进行注入。
</bean>
<!--实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用的两个值:
byName根据属性名称注入,注入值bean的id值和类属性名称一致
byType根据属性类型注入
-->
<bean id="emp" class="autowrie.Emp" autowire="byName">
</bean>
<bean id="dept" class="autowrie.Dept">
<property name="aname" value="学习部"></property>
</bean>
外部属性文件
1)配置连接池
-------引号人jar包
-------配置spring文件
2)引入外部属性文件配置数据库连接池
--------创建外部属性文件,properties格式文件,写数据库信息
--------把properties属性文件引入到spring配置文件中
先引入名称空间:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
。
xmlns:context="http://www.springframework.org/schema/context"
5)IOC操作Bean管理(基于注解)
1、什么是注解:
-------注解是代码的特殊标记,格式:@注解名称(属性名称=属性值)
-------注解可以用在类,方法、属性。
-------注解目的,简化xml配置。
2、Spring针对bean管理创建对象提供的注解
-------@Compoent:
-------@Service
-------@Controller
-------@Repository
--------上面的4个注解功能都是一样的,用来创建bean实例
3、基于注解方式实现对象创建
--------第一步、引入依赖
--------第二步、开启组件扫描(告诉spring类里面,要加上注解,去扫描那些类)
-------第三步、创建类,在类上面添加创建对象注解
开启组件扫描细节(告诉spring类里面,要加上注解,去扫描那些类)
<!--
use-default-filters="false" false表示自己配置规则
context:include-filter 设置扫描的内容
例子一:表示只扫描zhujie包中org.springframework.stereotype.Service的注解
-->
<context:component-scan base-package="zhujie" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!--
use-default-filters="false" false表示自己配置规则
context:include-filter 设置扫描那些内容不扫描
-->
<context:component-scan base-package="zhujie" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
注解方式属性的注入
@AuroWired (根据属性类型进行自动装配)
---------第一步把Service和dao对象创建好,在service和dao类添加创建对象的注解
---------第二步在service注入dao对象,在service和dao类添加创建对象注解
--------第三步在serviece注入到对象,在属性上面使用注解
@Qualifier (根据属性名称进行注入)
Qualifier要和AuroWired一起使用
@Resourc (可以根据类型注入,也可以根据名称注入)
@value(更具普通类型属性)
三、AOP
1)AOP概念
---------面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,提高开发效率
--------通俗描述:不通过修改源代码方式,在主干功能里面添加新的功能
2)底层原理
-------Aop底层使用动态代理
1)两种情况的动态代理
第一种、有接口的情况,使用JDK动态代理
****创建接口实现类代理对象,增强类的方法
第二种、无接口的情况,使用CGLIB动态代理
******创建子类的代理对象,增强类的方法
3)AOP(动态代理)
----------使用JDK动态代理,使用proxy类里面的方法创建代理对象
1)newproxyinstance方法第一个参数, 定义了由哪个ClassLoader对象来对生成的代理对象进行加载
2)第二个参数,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
3)第三个参数,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
1)创建接口定义方法
public interface UserDao {
public int add(int a,int b);
public String update(String a);
}
2)创建接口实现类,实现方法
public class UsrDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String a) {
return a;
}
}
3)使用proxy类创建接口代理对象
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfase={UserDao.class};
UsrDaoImpl usrDao = new UsrDaoImpl();
UserDao o = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfase, new UserDaoPosy(usrDao));
int add = o.add(1, 2);
System.out.println(add);
}
}
//创建代理对象代码
class UserDaoPosy implements InvocationHandler{
//把创建是谁的代理对象,把他给传递过来
//通过有参构造传递
private Object object;
public UserDaoPosy(Object object){
this.object=object;
}
//incoke写增强的逻辑
//proxy:你的代理对象 method:你的代理中的方法 args:你的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行"+method.getName()+"传递的参数"+ Arrays.toString(args));
//被增强后的方法执行
Object res = method.invoke(object, args);
//方法之后
System.out.println("方法之后执行"+object);
return res;
}
}
4)AOP(术语)
------连接点
类里面那些方法可以增强,这些方法被叫做连接点
------切入点
实际被真正增强的方法,被叫做切入点
------通知(增强)
实际增强的逻辑部分
通知有多种类型,前置通知,后置通知,环绕通知,异常通知,最终通知。
------切面
是动作,把通知应用到切入点的过程。
4)AOP(准备工作)
--------1、Spring矿建一般基于Aspecj实现AOP操作
1)什么是Aspecj
他不是spring组成部分,是独立的Aop框架,一般Aspecj和Sping一起使用,进行Aop操作
--------2、基于Aspecj实现Aop操作
1)基于xml方式实现
2)基于注解方式实现(经常使用)
--------3、在项目工程里面引入AOP相关依赖
-------4、切入点表达式
1)切入点表达式作用,知道对哪个类里面的那个方法增强
2)语法结构
execution([权限修饰符] [返回类型][类全路径][方法名称][(参数名字)]),通常*表示所有的权限修饰符
5)AOP(Aspecj注解实现操作)
-------创建类,在类里面定义方法
-------创建一个增强类(里面写你要增强的逻辑)
1)在增强类里面,创建方法,让不同方法代表不同的通知
--------进行通知配置
1)在spring配置文件中,开启注解的扫描
2)使用注解来创建user和userproxy对象
3)增强类上面添加注解@Aspect
4)在spring配置文件中开启生成代理对象
---------配置不同类型的通知
1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
@Before(vlaue=“切入点表达式”)前置通知
@After(vlaue=“切入点表达式”)后置通知
@AfterReturning(vlaue=“切入点表达式”)最终通知,返回值之后执行
@AfterThrowing(vlaue=“切入点表达式”)异常通知
@Around(vlaue=“切入点表达式”)环绕通知。 在方法之前和之后都会执行
<context:component-scan base-package="User"></context:component-scan>
<aopt:aspectj-autoproxy></aopt:aspectj-autoproxy>
//被增强类
@Service("user1")
public class User1 {
public void Add(String name){
System.out.println("被增强的类"+name);
}
}
//增强的类
@Service(value = "user1proxy")
@Aspect//生成代理对象
public class User1proxy {
@Before( value = "execution(* User.User1.Add(..))")
public void user1proxy_add(){
System.out.println("这是前置增强的方法");
}
@Test
public void qsh(){
ApplicationContext context=new ClassPathXmlApplicationContext("qsh01.xml");
User1 user1 = context.getBean("user1", User1.class);
user1.Add("覃圣航");
}
}
5)AOP(Aspecj注解实现操作优化)
相同的切入点抽取
1)定义一个方法
2)在方法上面加上切入点注解Poincur(value=“切入点表达式”)
public class User1proxy {
@Pointcut(value ="execution(* User.User1.Add(..))" )
public void Poinitt(){
}
@Before( value = "Poinitt()")
public void user1proxy_add(){
System.out.println("这是前置增强的方法");
}
@Test
三、jdbcTemplate
1)jdbc准备工作
------------什么是jdbcTemplate
1)Spring框架对jabc进行封装,使用jdbcTemplae方便实现对数据库操作
-----------准备工作
1‘)引入相关jar包
2)在spring配置文件配置数据库连接池
3)配置jdbctemplate对象
4)创建service类,创建dao类,在dao类注入jdbctemplate对象
public interface Dao_interface {
}
@Service("dao")
public class dao implements Dao_interface{
@Autowired
private JdbcTemplate jdbcTemplate;
}
public class service {
@Autowired
private Dao_interface dao;
}
1)操作数据库准备工作
-------对应数据库表创建实体类
-------编写service和dao
1)在dao进行数据库添加操作
2)update(String sql ,Objec… args )
第一个参数:sql语句,第二个参数:可变参数,设置sql语句值
public interface Dao_interface {
//添加的方法
void add(Book book);
}
@Service("dao")
public class dao implements Dao_interface{
@Autowired
private JdbcTemplate jdbcTemplate;
//添加的方法
@Override
public void add(Book book) {
//用 jdbcTemplate.update来实现增加删除修改
String sql="inert into book values(?,?,?)";
int update = jdbcTemplate.update(sql, book.getUserId(), book.getUsername(), book.getUstatus());
System.out.println(update);
}
}
public class service {
@Autowired
private Dao_interface dao;
public void addBook(Book book){
dao.add(book);
}
}
----查询操作
返回一个值:
第一个参数是sql语句,第二个是返回值类型
返回对象:
----多条语句执行
四、 事物管理
1)什么是事务
1)事务是数据库操作最基本的单元,逻辑上一组操作,要么成功,要么失败,如果一个失败那所有的操作都失败
2)事务的特性:原子性(要么成功要么失败)、一致性(操作前和操作后总量不变)、隔离性(在多事务操作时,之间没有影响)、持久性()
2)事务操作(搭建事务操作环境)
-----------创建数据库表,添加记录
-------创建service,搭建dao,完成对象的创建和注入关系
1)在service注入dao,在dao注入jdbctemplate,在jdbctemplate注入DateSource
------在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)
public interface UserDao {
public void addMoney();
public void reduceMoney();
}
@Repository("userdaoimpl")
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
//A转账100给B
@Override
public void reduceMoney() {
String sql="update t_account set money=money-? where username";
jdbcTemplate.update(sql,100,"lucy");
}
@Override
public void addMoney() {
String sql="update t_account set money=money+? where username";
jdbcTemplate.update(sql,100,"mary");
}
}
@Service("userservice")
public class UserService {
//注入dao
@Autowired
@Qualifier("UserDaoimpl")
private UserDao userdao;
public void accountMoney(){
//A少100
userdao.addMoney();
//b多100
userdao.reduceMoney();
}
}
2)事务操作(事务场景出现)
上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常。
1)下面问题如何解决
使用事务进行解决
2)操作过程。开启事务操作、进行业务操作、没有异常关闭异常提交事务,出现异常事务回滚
public void accountMoney(){
//A少100
userdao.addMoney();
//模拟异常,如此a会少100但是b不会增加
int a=10/0;
//b多100
userdao.reduceMoney();
}
2)事务操作(Spring事务管理介绍)
-----------事务添加到javaee三层架构里面service层中(业务逻辑层)
-----------在Spring进行事务管理操作
1)有两种方式:编程式事务管理和声明式事务管理(常使用)
--------声明事务管理
1)基于注解方式
2)基于xml配置文件方式
--------在Spring进行声明式事务管理,底层使用Aop原理
---------Spring事务管理API
1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
2)事务操作(注解声明式事务管理)
-----------在spring中配置文件配置事务管理器
-----------在Spring配置文件中,引入tx名称空间
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
-----------开启事务注解
-----------在service的类上面(或者service类的方法上)添加事务注解
1)@Transactional,这个注解可以添加到类上面,也可以添加到方法上面
2)如果添加到类上面,这个类里面所有的方法都添加了事务
3)添加的方法,为这一个方法添加事务
2)事务操作(@Transactional参数配置)
在service类上面添加注解@Transactional,在这个注解里面可以配置事务的相关参数
----------propagation:事务的传播行为(@Transactional(propagation = Propagation.REQUIRED))
1)多事务方法直接进行调用,这个过程中事务时如何进行管理的。例如:一个事务方法调用一个不是事务的方法,不是事务方法调用是事务方法…。
----------ioslation:事务隔离级别(@Transactional(isolation = Isolation.SERIALIZABLE))
1)事务中有特性隔离性,多事务操作之间不会产生影响。不考虑隔离性会产生很多问题
2)产生的三个问题:脏读、不可重复读、虚读
3)脏读:一个未提交事务读取到另一个未提交事务的数据
4)不可重复读:一个未提交的事务读取到提交了的事务添加的数据
5)虚读:一个未提交的事务读取到提交了的是事务添加的数据
6)设置隔离级别,解决问题
----------timeout:超时时间
1)事务在多长时间内提交,若不提交就会回滚
2)默认值:-1,表示不超时,设置以秒为单位
----------readOnly:是否只读
1)读:查询操作,写:添加修改操作
2)默认值false,读写操作
3)设置为true,只可以读操作
----------rollbackFor:回滚
1)设置查询那些异常进行事务回滚
----------noRollbackfor:不回滚
2)设置出现那些异常不进行事务回滚
spring5新特性
Spirng框架自带了通用的日志封装(官方建议使用log4j2)
1)引入log4j2相关jar包
2)创建Log4j2.xml文件(这个名字是固定的)
Spring框架核心容器支持@Nullable注解
@Nullable注解可以使用在方法、属性、参数上面,表示方法可以返回为空、属性值、参数值可以为空
Spring框架核心容器支持函数式风格GenericApplicationContext
可以使用java8中的Lambda表达式
Spring支持整合JUnit5
------------整合Junit4
1)引入spring针对测试的依赖
2)创建测试类,使用注解(@Test)方式完成
------------整合Junit5
1)引入Junit5的jar包
2)创建测试类,使用注解方式完成