spring

spring

Spring基础

spring由,IOC控制反转,创建对象给Spring管理。AOP面向切面,不修改源代码进行功能的增强

特点

  1. 方便解耦度

  2. Aop编程支持

  3. 方便测试

  4. 方便和其他框架整合

  5. 方便进行事务的操作

  6. 降低API的开发难度

IOC容器

底层原理

把对象创建和对象调用的过程交给Sring管理,IOC降低耦合度,底层原理(控制/反转)XML,工厂模式,反射

ioc过程

1.有xml配置文件,配置创建对象

<bean  id = "对象名称"  class  = "对象文件地址"></bean>
<bean id="User" class="Spring5.text.text1"/>

2.有service和dao类创建工厂类

class UserFactory{
    public static Userdao getDao(){
        String class value = class.属性值;
            //xml解析
            //通过反射创建对象
         Class class = Class.forName(Class.Value);
        return (UserDao)class.newInstance();
        //强转得到
            
    }
}

IOC接口(容器)

思想基于IOC容器,IOC本质是对象工厂,Spring提供IOC的两种方式实现

(1)BeanFactory,IOC基本实现Spring内部使用接口,不提供开发人员使用

(2)ApplicationContext,BeanFactory的子接口提供更强大的接 口

区别:

BeanFactory加载时不会创建对象在获取时/使用时才创建对象,BeanFactory是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。

ApplicationContext加载文件时就和把配置文件对象进行创建,ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能

(3)ApplicationContext接口实现类,FileSystem电脑盘加载,ClassPath编译src下文件

如何实现Ioc容器

  1. 配置文件中指定需要扫描的包的路径

  2. 定义注解,分别表示访问控制层,业务服务层,数据持久层,依赖注入注解,获取配置文件注解

  3. 从配置文件中获取需要扫描的包路径,获取到当前路径下文件信息及文件夹信息,我们将当前路径下所有以。class结尾文件添加到一个set集合中进行存储

  4. 变量这个set集合获取类上指定注解的类,并交给ioc容器,定义一个安全的map集合来存储这些对象

  5. 遍历这个ioc容器。获取到每一个类的实例,判断里面是否有依赖其他类的实例,然后进行递归注入

IOC操作bean管理(两个操作)

(1)spring创建对象(2)Spring注入属性

进行bean管理操作

(1)基于xml配置文件属性

(2)基于注解方式实现

  1. 基于xml方式。在标签里可以加响应属性bean有很多属性,id唯一标识,class类名路径,创建对象默认是无参构造方法,完成对象的创建

  2. 基于xml方式注入属性。DI依赖注入,注入属性,DI是IOC的一种实现,DI是IOC的具体实现

  3. 使用set方法注入,创建类,属性,对应的set方法,在Spring配置文件中进行配置对象,注入shuxing

  4. 使用有参数构造方法注入,创建类,对应属性,创建属性对应的有参构造方法,在Spring文件中进行配置

  5. P名称空间注入,使用p名称空间注入,简化xml配置方式,添加p名称空间配置文件,进行属性注入在bean标签里

Spring的IOC有三种注入方式 :构造器注入、set方法注入、根据注解注入。

set方法注入

public class Book {
    private String bname;
    private String bauthor;
    public void setBname(String bname) {
        this.bname = bname;
    }
    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
}

(2)在spring文件中配置对象,配置属性注入

​
<!--set注入属性-->
    <bean id="book" class="com.Spring5.Book">
        <!--使用property属性完成属性注入
        name:类里面属性名称
        value:向属性注入值
        -->
        <property name="bname" value="易筋经"></property>
        <property name="bauthor" value="达摩老祖"></property>
    </bean>

(3)测试文件

@Test
    public void TextBook1(){
        //加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //获取配置创建对象
        Book book = context.getBean("book", Book.class);
        System.out.println(book);
        book.textDemo();
    }

构造器注入

创建类,定义属性,创建属性对应有参数构造方法

public class Orders {
    private String oname;
    private String address;
    //有参数构造
    public Orders(String oname, String address) {
        this.oname = oname;
        this.address = address;
    }
}

<!--有参构造-->
    <bean id="orders" class="com.Spring5.Orders">
        <constructor-arg name="oname" value="电脑"></constructor-arg>
        <constructor-arg name="address" value="China"></constructor-arg>
    </bean>

测试类

  @Test
    public void TextOrders1(){
        //加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //获取配置创建对象
        Orders Orders = context.getBean("orders", Orders.class);
        System.out.println(Orders);
        Orders.OrdersText();
    }

xml注入其他类型属性

  1. 字面量,设置属性的固定值

    (1)null值

    <property name="address">
                <null></null>
            </property>

    (2)属性值包含特殊符号

    吧<>进行转义&lt,&gt

    吧带特殊符号内容写到CDATA

    <!--属性值中包含特殊符号-->
            <property name="bauthor">
                <value>
                    <![CDATA[<<南京>>]]>
                </value>
            </property>

外部bean

(1)创建两个类Service和Dao

(2)在sevice中调用Dao里的方法

(3)在spring文件中进行配置

public class UserService {
    //创建UserDao属性,生成set方法
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service>>>>>>>>>>>>");
        userDao.update();
    }
}
​
------------------------------------------------------------------------------------------------
    
<!--service对象创建和Dao对象-->
    <bean id="userService" class="com.Spring5.service.UserService">
        <!--注入UserDao对象
        name属性值,类里面属性名称
        ref 创建userDao对象bean标签id值-->
        <property name="userDao" ref="useDao"></property>
    </bean>
    <bean id="useDao" class="com.Spring5.dao.UserDaoImpl"></bean>

内部bean和级联赋值

(1)一对多,部门跟员工

(2)实体类表示一对多,员工表示所属部门,使用类对象进行表示

(3)在spring进行配置

//员工类
public class Emp {
    private String ename;
    private String gender;
    private Dept dept;
    public Dept getDept() {
        return 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;
    }
    public void add(){
        System.out.println(ename + "::" + gender + "::" + dept);
    }
}
​
--------------------------------------------------------------
//部门类
public class Dept {
    private String dname;
    public void setDname(String dname) {
        this.dname = dname;
    }
    @Override
    public String toString() {
        return "Dept{" +
                "dname='" + dname + '\'' +
                '}';
    }
}
​
-----------------------------------------------------------------
    <!--内部bean-->
    <bean id = "emp" class="com.Spring5.bean.Emp">
        <!--设置普通属性类型-->
        <property name="ename" value="lucy"></property>
        <property name="gender" value="女"></property>
        <!--设置对象属性类型-->
        <property name="dept">
            <bean name="dname" class="com.Spring5.bean.Dept">
                <property name="dname" value="a保安部"></property>
            </bean>
        </property>
    </bean>
    

注入属性-级联赋值

 <!--级联赋值--> 
    <bean id = "emp" class="com.Spring5.bean.Emp">
        <!--设置普通属性类型-->
        <property name="ename" value="lucy"></property>
        <property name="gender" value="女"></property>
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.Spring5.bean.Dept">
        <property name="dname" value="财务部"></property>
    </bean>
    
 ------------------------------------------------
    <bean id = "emp" class="com.Spring5.bean.Emp">
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
        <property name="dept.dname" value="人事部"></property>
    </bean>
    <bean id="dept" class="com.Spring5.bean.Dept">
        <property name="dname" value="财务部"></property>
    </bean>
        

xml属性注入

public class Stu {
    //数组类型
    private String[] courses;
    //List集合类型
    private List<String> list;
    //map集合类型
    private Map<String,String> map;
    //set集合类型
    private Set<String> set;
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
}
-------------------------------------------------------------------
   
    <!--集合类型属性注入-->
    <bean id="stu" class="com.Spring5.stu.Stu">
        <!--数组类型属性注入-->
        <property name="courses">
            <array>
                <value> java </value>
                <value> 数据库 </value>
            </array>
        </property>
        <!--List集合类型属性注入-->
        <property name="list">
            <array>
                <value>z展现</value>
            </array>
        </property>
        <!--map集合类型属性注入-->
        <property name="map">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="PHP" value="php"></entry>
            </map>
        </property>
        <!--set集合类型属性注入-->
        <property name="set">
            <set>
                <value>mySql</value>
                <value>Redis</value>
            </set>
        </property>
    </bean>
    
    

集合设置对象类型值

<bean id="stu" class="com.Spring5.stu.Stu">
<!--注入list集合类型,值是对象-->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>
        
    </bean>
    <bean id="course1" class="com.Spring5.stu.Course">
        <property name="cname" value="Spring5框架"></property>
    </bean>
    <bean id="course2" class="com.Spring5.stu.Course">
        <property name="cname" value="MyBatista框架"></property>
    </bean>
    
    -------------------------------------------------------------------
    
     private List<Course> courseList;
​
    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }
    
    
    -----------------------------------------------------
    
    public class Course {
    private String cname;
​
    public void setCname(String cname) {
        this.cname = cname;
    }
}

集合注入提取出来

<!--提取List集合类型注入提取-->
    <util:list id="bookList">
        <value> 易筋经</value>
        <value> 九阴真经</value>
        <value> 九阳神功</value>
    </util:list>
    <!--提取list集合进行注入-->
    <bean id="book" class="com.Spring5.stu.Book">
        <property name="list" ref="bookList"></property>
    </bean>
    
   ---------------------------------------------------
        
  public class Book {
    private List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    public void text() {
        System.out.println(list);
    }
}

IOC操作bean管理

Spring有两种bea,普通bean和工厂bean。普通bean,定义什么类型返回什么类型。工厂Bean,定义类型和返回类型不同

bean的作用域

在Spring中设置bean是单实例还是多实例,默认bean是单实例,spring中有默认属性scope用于设置单实例/多实例

scope属性值有singleton表示单实例,prototype表示多实例,

设置singleton时加载Spring文件时对象就会被创建,设置Prototype时在调用getBean时创建对象,加载Spring文件时不会创建对象

bean的生命周期

  1. 通过构造器创建bean实例(无参构造)

  2. 为bean的属性值和对其他bean引用(调用set)

  3. 把bean实例传递到bean后置处理器方法postProcessBeforeInitialization

  4. 调用bean的初始化方法

  5. 把bean实例传递到bean后置处理器方法postProcessAfterInitialization

  6. bean可以使用(对象获取到)

  7. 当容器关闭时,调用bean的销毁(需要配置方法)

@Test
    public void test2(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("创建bean实例");
        //手动调用销毁
        context.close();
​
    }
​
-----------------------------------------------------
    
    public class Orders {
    public Orders() {
        System.out.println("执行无参构造方法创建bean实例");
​
​
    }
​
    private String oname;
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("调用set方法设置属性值");
    }
    //创建执行初始化方法
    public void initMethod(){
        System.out.println("执行初始化方法");
    }
​
    //创建执行销毁化方法
    public void destroyMethod(){
        System.out.println("销毁");
    }
}
​
---------------------------------------------------------------
    
    <bean id="orders" class="com.Spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
        <property name="oname" value="手机"></property>
     </bean>
     
 ---------------------------------------------------------------
        //配置后置处理器
        public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前执行");
        return null;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后执行");
        return null;
    }
}
​

xml自动装配

根据指定的装配规则(属性名称,属性)Spring自动匹配属性注入

bean标签内有属性autowire,有两个常用的属性byName/byType,byName,bean内的id和属性名称一样,byType根据属性类型注入

<!--实现自动装配
    bean标签属性autowire配置自动装配
    byName,bean内的id和属性名称一样,
    byType根据属性类型注入-->
    <bean id="emp" class="com.Spring5.autowire.Emp" autowire="byName">
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.Spring5.autowire.Dept"></bean>
    
        
  -------------------------------------------------------
        
        
    public class Emp {
    private Dept dept;
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }
    public void text() {
        System.out.println(dept);
    }
}
​
-------------------------------------------------
    
    public class Dept {
    @Override
    public String toString() {
        return "Dept{}";
    }
}

外部属性

(1)配置数据库信息

<!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassLoader" value="com.mysql.jdbc.Driver"></property><!--驱动名称-->
        <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

(2)引入外部属性文件

prop.driverClass = com.mysql.jdbc.Driver
prop.url = jdbc:mysql://localhost:3306/userDb
prop.userName = root
prop.password = root

把外部properties属性文件引入到spring文件中

引入contest

xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd“
​
    
<!--引入外部文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassLoader" value="${prop.driverClass}"></property><!--驱动名称-->
        <property name="url" value="${prop.url}"></property>
        <property name="username" value="${prop.userName}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>

基于注解操作bean

1.什么是注解

  1. 是代码的特殊标记,格式 @注解名称( 属性名称 = 属性值 ,属性名称 = 属性值)

  2. 使用注解,可以作用在类,属性,方法上

  3. 使用注解目的,简化xml配置

2.bean管理创建对象提供注解

  1. @Compoent,普通组件

  2. @Service,一般用于业务逻辑层和service层

  3. @Controller,一般用于web层

  4. @Repository,用于持久层

  5. 四个功能都一样,都可以创建bean

3.基于注解实现对象创建

 <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">
​
<!--1.开启组件扫描
          扫描多个包,多个包用逗号隔开
    扫描上层目录
    -->
    <context:component-scan base-package="com.Spring5"></context:component-scan>
    
        
 -------------------------------------------------------------------------------------------------------
        
        
   //注解里面value可以不写默认名称为类名称首字母小写
@Component(value = "userService")
public class UserService {
    public void add(){
        System.out.println("service dao");
    }
}
​
---------------------------------------------------------------------
    
    //测试
     @Test
    public void text01(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }
​

(4)细节问题开启组件扫描

<!--示例1-->
    <context:component-scan base-package="com.Spring5" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

use-default-filters="false"表示不使用默认的filters,使用自己的配置的filter

context:include-filter 扫描设置那些内容,在注解里只扫描带这个注解的类

<!--示例2-->
    <context:component-scan base-package="com.Spring5">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

context:exclude-filter 意思是除了这个注解不扫描其他注解都扫描

(5)基于注解实现属性注入

  1. @AoutWired 根据属性类型注入,自动装配

  2. @Qualifier 根据属性名称进行注入,使用得和@AoutWired一起配合使用

  3. @Resource 可以根据类型也可以根据属性名称注入

  4. @Value 注入普通类型属性

  1. 吧service和dao对象创建在Service和Dao中添加对象注入

  2. service注入dao,service添加dao属性,属性上使用注解

@Service
public class UserService {
    /**
     * 定义dao属性
     * 不需要添加set方法
     * 添加注入属性注解
     */
    @Autowired
    private UserDao userDao;
    public void add(){
        System.out.println("service dao");
        userDao.add();
    }
}
​
--------------------------------------------------
  @Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("dao add.................");
    }
}  

(6)完全注解开发

创建配置类

@Configuration
@ComponentScan(basePackages = {"com.Spring5"})
public class SpringConfig {
    
}

测试方法

@Test
    public void text02(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

Aop概念

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。

不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,

而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用、

底层原理

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,创建接口实现类的代理对象增强类的方法

CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。创建当前的子类的代理对象,增强类的功能

JDK动态代理

  1. 使用jdk动态代理 , 使用Proxy类的方法可以实现动态代理

  2. 调用newProxyInstance方法

    static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)

  3. 方法有三个参数,第一个类加载器,第二个增强方法所在的类,这个类实现接口可以是多个,第三个这个接口InvocationHandler,创建代理对象写增强的部分

代码

创建接口,定义方法。创建接口实现类,使用Proxy创建接口代理对象

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
​
​
        UserDaoImpl userDao = new UserDaoImpl();
        //强转
        UserDao dao =(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        int result = dao.add(1, 2);
        System.out.println(result);
    }
}
class UserDaoProxy implements InvocationHandler{
    //把创建是谁的代理对象,吧谁传递过来,多种方法
    //有参构造
    private Object obj;
    public UserDaoProxy(Object obj){
        this.obj = obj;
    }
    //增强逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前
        System.out.println("方法之前执行" + method.getName() + "传递的参数。。" + Arrays.toString(args));
        //被增强方法执行
        Object res = method.invoke(obj , args);
        //方法之后
        System.out.println("方法之后执行那个" + obj);
        return res;
    }
}
​
-----------------------------------------------------------------------
    
       
    public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
​
        //匿名内部类
        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
}
        
        
public class UserDaoImpl implements UserDao {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    @Override
    public String update(String id) {
        return id;
    }
}
        
public interface UserDao {
    public int add( int a,int b);
    public String update(String id);
}
​

Aop术语

  1. 连接点,类中的方法可以增强,这些方法称为连接点

  2. 切入点,实际被增强的方法,称为切入点

  3. 通知,实际增强逻辑部分称为通知(增强),通知有多种类型

    前置通知 ,环绕通知 , 异常通知 ,后置通知 ,最终通知

  4. 切面(动作),吧通知应用到切入点的过程

Aop操作

  1. Spring一般基于AspectJ实现Aop

    AspectJ不是Spring部分,独立的Aop框架,吧AspectJ和Spring一起使用,进行Aop操作

  2. 基于AspectJ实现Aop操作

    (1)基于Xml实现

    (2)基于注解方式实现

  3. 引入相关jar包

  4. 切入点表达式

    (1)切入点表达式作用,哪个类,那个方法进行增强

    (2)语法结构execution([权限控制符] [返回类型] [类全路径] [方法名称] [参数列表])

    对类增强

    execution(* com.Spring5.aopanno.User.add(..))

    所有方法增强

    execution(* com.Spring5.aopanno.User.* (..))

AspectJ注解

  1. 创建类,在类中定义方法

  2. 创建增强类(编写增强逻辑)

    (1)在增强类里创建方法,让不同的方法代表不同的通知

  3. 进行通知的配置

    (1)在Spring文件中开启注解扫描

    (2)使用注解创建User和Userproxy对象

    (3)在增强类中添加注解@Aspect

    (4)在Spring配置文件中开启生成代理对象

  4. 配置不同类型通知

    (1)在增强类中,作为通知方法,上面添加通知类型注解,使用切入点表达式配置

  5. 相同切入点的抽取

  6. 多个增强类型,多个方法同时进行增强,设置增强优先级

    (1)在增强类上添加注解@order(数字类型值),数字越小优先级越高。

  7. 完全使用注解开发

    (1)创建配置类,不需要xml配置文件

    @Configuration
    @ComponentScan(basePackages = {"com.Spring5"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
@Component
@Aspect //生成代理对象
//增强类
public class UserProxy {
    //相同切入点抽取
    @Pointcut(value = "execution(* com.Spring5.aopanno.User.add(..))")
    public void PointDemo(){
    }
    //前置通知
    //Before表示作为前置通知
    @Before(value = "PointDemo()")
    public void before1() {
        System.out.println("before1................");
    }
    //前置通知
    //Before表示作为前置通知
    @Before(value = "execution(* com.Spring5.aopanno.User.add(..))")
    public void before() {
        System.out.println("before................");
    }
    //最终通知
    @AfterReturning(value = "execution(* com.Spring5.aopanno.User.add(..))")
    public void AfterReturning() {
        System.out.println("AfterReturning................");
    }
    //后置通知
    @After(value = "execution(* com.Spring5.aopanno.User.add(..))")
    public void after() {
        System.out.println("after........................");
    }
​
    //异常通知
    @AfterThrowing(value = "execution(* com.Spring5.aopanno.User.add(..))")
    public void AfterThrowing() {
        System.out.println("AfterThrowing........................");
    }
    //环绕通知
    @Around(value = "execution(* com.Spring5.aopanno.User.add(..))")
    public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Around.......................");
        //被增强的方法
        proceedingJoinPoint.proceed();
        System.out.println("Around.......................");
    }
}
​
---------------------------------------------------------
    
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
​
​
    <!--开启注解扫描-->
    <context:component-scan base-package="com.Spring5.aopanno"></context:component-scan>
    <!--开启AspectJ生成代理对象-->
    <aop:aspectj-autoproxy>
​
    </aop:aspectj-autoproxy>
    
 ------------------------------------------
  
        @Component
public class User {
    public void add(){
        System.out.println("add................");
    }
}
​
​
​

配置文件

(1)创建两个类,增强类和被增强类

(2)在spring配置文件中创建两个;类对象

(3)在Spring配置文件中配置切入点

 <!--创建对象-->
    <bean id="book" class="com.Spring5.AopXml.Book"></bean>
    <bean id="bookProxy" class="com.Spring5.AopXml.BookProxy"></bean>
    <!--配置Aop增强-->
    <aop:config>
       <!-- 切入点-->
        <aop:pointcut id="p" expression="execution(* com.Spring5.AopXml.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <!--增强作用在具体的方法上-->
            <aop:before method="Before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>

JDBCTemplate

1.什么是jdbcTemplate

(1)Spring对JDBC进行封装,使用jdbcTemplate方便进行数据库操作

Spring的事务管理

通过aop管理实务,根据aop通过实现TransactionInterceptor调用invoke实现具体逻辑

1.先做准备工作,根据注解判断哪些事物需要执行

2.关闭自动提交,获取连接,开启事务

3.执行sql逻辑

4.若执行失败,获取连接对象,调用rollback方法回滚成功则commit提交

5.事务执行完成后清除相关事务信息

1.什么是事务

(1)事务是数据库操作最基本单元,逻辑上的一组操作,要么都成功要么都失败

事务的四个特性(ACID)

  1. 原子性

  2. 一致性

  3. 隔离性

  4. 持久性

事务环境搭建

  1. 创建数据库

  2. 创建service 搭建 dao 完成对象创建和注入关系

    (1)service注入dao在dao中注入JDBCtemplate,在JDBC中注入DataSource

    (2)xml配置

    组件扫描

    数据库连接池

    jdbcTempalte对象,注入DataSource

  3. 在dao创建两个方法,多钱和少钱,在Service创建方法(转账方法)

  4. 正常执行无问题,若出现问题或异常则有问题

    解决上面问题用事务解决

    事务操作过程

    1.开启事务 2.进行事务操作 3.没有发生异常 4.出现异常事务回滚

spring事务管理介绍

事务一般加到service层

在Spring中进行事务管理,有两种,编程式管理和声明式事务管理

声明式事务管理(1)基于注解方式(2)基于xml配置文件方式

Spring进行声明式事务管理,底层使用Aop原理

Spring事务管理API,提供了一个接口,代表事务管理针对不同的框架,实现不同的实现类

注解声明式事务管理

  1. 在spring配置文件事务管理器

  2. 在spring配置文件。开启事务注解

    (1)在spring配置文件中引入名称空间tx

  3. 在service类上获得Service类上添加事务注解

    (1)Transactional,可以添加到类上,也可以添加在方法上面

    (2)如果吧这个注解添加到类上,这个类里所有方法都添加事务

    (3)如果添加到方法上则为这个方法添加事务

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
​
​
    <!--组件扫描-->
    <context:component-scan base-package="com.Spring5"/>
    <!--数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>
    <!--JDBCTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
​
    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
​
    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
​
</beans>
​
-------------------------------------------------------------------------------------------------------
​
@Service
@Transactional
public class UserService {
    //注入dao
    private final UserDao userDao;
​
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
    //转账方法
    public void accountMoney(){
        userDao.reduceMoney();
        //模拟异常
        int i = 10 / 0;
        userDao.addMoney();
       }
  }
  
----------------------------------------------------------------------------------
    @Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
​
    @Override
    public void addMoney() {
        String sql = "update t_account set money = money - ? where username = ?";
        jdbcTemplate.update(sql,100,"lucy");
    }
​
    @Override
    public void reduceMoney() {
        String sql = "update t_account set money = money + ? where username = ?";
        jdbcTemplate.update(sql,100,"mary");
    }
}
​

声明式事务管理参数配置

  1. service类上添加注解@Transactional,这注解可以配置事务相关参数

  2. 事务传播属性propagation

    (1)多事务方法直接进行调用,这个过程中这个事务是如何进行管理的

    事务传播行为,事务方法:对数据库表数据进行操作

    spring事务传播行为有7种

    REQURED如果add方法本身有事务,调用update方法后,updata使用add的事务,若add方法,没有事务,调用update后创建新的事务
    REQURED_NEW使用add调用update方法,无论add是否有事务,都创建新的事务
    SUPPORTS如果有事务运行当前方法就在事务内运行,否则可以不运行在事务中
    NOT_SUPPORTS当前方法不运行在事务中,若有事务正在执行,则方法挂起
    MANDATORY当前事务必须执行在事务中,若没有事务正在运行,则抛出异常
    NEVER当前方法不应该运行在事务中,如果有正在运行的事务,抛出异常
    NESTED如果有事务在运当前方法,当前的方法就应该在事务的嵌套事务运行,否则就启动一个新的事务,并在自己的事务内运行。
    @Transactional( propagation = Propagation.REQURED)

  3. 事务隔离级别ioslation

    事务特性成为隔离性,多事务之间不会产生影响,不考虑隔离性,会产生很多问题

    有三个读的问题 脏读,不可重复读,幻读

    (1)脏读,一个未提交事务读取到另一个未提交事务的数据

    (2)不可重复读,一个未提交事务读取到另一个提交事务,修改数据

    (3)虚(幻)读,一个未提交事务读取到另一提交事务添加数据

    设置事务隔离性解决读的问题

    脏读不可重复读虚(幻)读
    已读未提交READ UNCOMMITTED×××
    未读已提交READ COMMITTED××
    可重复读REPEATABLE READ×
    串行化SERIALIZABLE
  4. 超时时间timeOut

    事务在一定时间内进行提交,如果不提交则进行回滚

    默认是-1,以时间秒为单位进行计算

  5. 是否只读

    (1)读查操作,写修改数据删除操作

    (2)readOnly默认为false,可查询,可修改

    (3)设置true,只能查询

  6. 回滚rollbackFor

    设置事务回滚流

  7. 不回滚norollbackFor

    设置出现那些异常不进行事务回滚

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值