Spring框架学习笔记

1.Spring

1.1简介

是一个轻量级控制反转(ioc)和面向切面(AOP)的容器框架

  • 目的:解决企业开发复杂性

  • 理念:使现有技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架

  • SSM: SpringMVC+Spring+Mybatis

1.2优点

  • Spring是一个开源的免费的框架

  • Spring是一个轻量级的,非入侵式的框架

  • 控制反转(IOC),面向切面编程(AOP)

  • 支持事务的处理,对框架整合的支持

Spring就是一个轻量级的控制反转和面向切面编程的框架

1.3组成

1.4 拓展

现代化的Java开发就是基于Spring的开发

  • SpringBoot

    • 一个快速开发的脚手架

    • 基于SpringBoot可以快速开发单个微服务

    • 约定大于配置

  • SpringCloud

    • 基于SpringBoot实现

弊端:发展了太久违背了最初的理念!配置十分繁琐(“配置地狱”)

2. IOC

  1. UserDao接口

  2. UserDaolmpl实现类

  3. UserService业务接口

  4. UserServicelmpl业务实现类

IOC是一个容器

2.1 IOC底层原理

控制反转--依靠DI依赖注入

  • 降低耦合度

原理:

xml解析+工厂模式+反射

2.2 IOC接口(BeanFactory)

  1. IOC的思想基于IOC容器,底层就是对象工厂

  2. Spring提供两种实现方式

    1. BeanFatory:IOC最基本的实现,开发中一般不使用

      加载配置文件时不会创建对象,在获取或使用对象时才会创建对象

    2. ApplicationContext:BeanFatory的子接口,开发人员使用

      加载配置文件时,就会创建配置文件中的对象(例如服务器启动时就将对象创建完毕)

  3. ApplicationContext实现类

2.3 IOC操作Bean管理(基于xml配置文件set方法)

Bean管理:

  1. 由Spring创建对象

  2. 由Spring注入属性

基于xml配置文件创建对象并注入属性

  • xmlns

    • 用于指定命名空间,当命名空间不同时,同样的词条代表不同的含义

    • 例如:html中的list与java中的list出现在同一份xml文档中,此时就需要指定命名空间

  • xsi:schemalocation

    • 指定了XML namespace和对应的XSD(Xml schema definition)的位置关系

创建对象:

<?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="hello" class="com.wang.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>
​
​
</beans>

使用bean标签并添加属性

  • 常用属性

    • id属性(对象的别名),唯一的标识

    • class属性(对象的类的全路径)

创建对象时,默认执行无参构造方法(没有无参方法就会报错)

注入属性:

DI(依赖注入),就是输入属性(前提是在创建对象的过程中DI)

  1. set方法注入

  2. 有参构造注入

package com.wang.pojo;
//不使用Spring方法
public class Book {
​
    private String bname;
​
    public void setBname(String bname) {
        this.bname = bname;
    }
​
    public Book(String bname) {
        this.bname = bname;
    }
​
    public static void main(String[] args) {
​
        //原始方式set方法注入
        //Book book = new Book();
       // book.setBname("abc");
​
        //有参构造注入
        Book book = new Book("abc");
​
​
​
    }
}
​

Spring DI方法:

在Spring配置文件配置对象创建,配置属性注入

<?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="book" class="com.wang.pojo.Book">
        
        <property name="bname" value="易经"/>
        <property name="author" value="我"/>
​
​
    </bean>
​
​
</beans>

package com.wang.pojo;
​
public class Book {
    //不能添加有参构造方法
    private String bname;
    private String author;
​
    public void setBname(String bname) {
        this.bname = bname;
    }
​
    public void setAuthor(String author) {
        this.author = author;
    }
​
    public void Prin(){
        System.out.println(this.author);
        System.out.println(this.bname);
    }
​
}
​
​

2.4 IOC操作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="book" class="com.wang.pojo.Book">
​
        <constructor-arg name="bname" value="易经"></constructor-arg>
        <constructor-arg name="author" value="你"></constructor-arg>
​
    </bean>
​
​
</beans>

//Java   main函数代码不变

2.5 注入其他属性

字面量:

  • null值

  • 属性值包含特殊符号

<!-- 向属性里设置空值-->
<property name="author" value="我"></property>
        <property name="bname" >
            <null>
            </null>
        </property>
​
​

 <!-- 向属性值中添加特殊符号
            1.将尖括号进行转义,&lt;
            2.带有特殊符号的写到CDATA
        -->
        <property name="bname" value="&lt;&lt;难京&gt;&gt;"></property>
        <property name="author" >
            <value><![CDATA[<<南京>>]]></value>
        </property>

注入属性-外部Bean,内部Bean,级联赋值

  • 外部Bean

package com.wang;

import com.wang.dao.UserDao;
import com.wang.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBean {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();
    }
}
<?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="userService" class="com.wang.service.UserService">
        <property name="userDao" ref="userDaoImp"></property>
    </bean>
    <bean id="userDaoImp" class="com.wang.dao.UserDaoImp"></bean>

</beans>

  • 内部Bean

当存在一对多的关系时,使用内部Bean

例如员工和部门

<?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="emp" class="com.wang.test.Emp">
        <property name="ename" value="wdd"></property>
        <property name="gender" value="男"></property>
        <property name="dept" >
            <bean id="dept" class="com.wang.test.Dept">
                <property name="dname" value="开发部"></property>
            </bean>
        </property>
        
    </bean>

</beans>

  • 级联赋值

<?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="emp" class="com.wang.test.Emp">
        <property name="ename" value="wdd"></property>
        <property name="gender" value="男"></property>
        <property name="dept" ref ="dept"></property>
    </bean>
    <bean id="dept" class="com.wang.test.Dept"
          <property name="dname" value="开发部"></property>
     </beans>

</beans>

2.6 注入集合属性

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 集合类型属性注入-->
    <bean id="stu" class="spring5.Stu">
        <!-- 数组类型属性-->
        <property name="courses">
            <array>
                <value>java课程</value>
                <value>数据库课程</value>
            </array>
        </property>
        <!-- list类型属性-->
        <property name="list">
            <list>
                <value>zhangsan</value>
                <value>xiaosan</value>
            </list>
        </property>
        <!-- map类型属性-->
        <property name="maps">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="PHP" value="php"></entry>
            </map>
        </property>
        <!-- set类型属性-->
        <property name="sets">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>
    </bean>

</beans>

<!-- 注入list类型属性,值是对象-->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>

2.7 FactoryBean

Bean和FactoryBean

  1. Bean:

    • 在配置文件定义的bean类型就是返回类型

  2. FatoryBean:

    • 在配置文件中定义的bean类型可以和返回类型不同

FatoryBean的实现:

  1. 创建类,让这个类实现接口FactoryBean

  2. 实现接口中的方法,在实现的方法中定义返回的bean类型

package com.wang.test;

import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean {

    @Override
    public Dept getObject() throws Exception {
        Dept dept = new Dept();
        dept.setDname("开发部");
        return dept;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}
<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd"
        >
    <bean id="mybean" class="com.wang.test.MyBean">
    </bean>
</beans>

package com.wang;

import com.wang.dao.UserDao;
import com.wang.pojo.Book;
import com.wang.service.UserService;
import com.wang.test.Dept;
import com.wang.test.Emp;
import com.wang.test.MyBean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class TestBean {
    public static void main(String[] args) throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Dept myBean = context.getBean("mybean", Dept.class);
        System.out.println(myBean.getDname());

    }
}

2.8 Bean管理

Bean的作用域

可以设置bean对象是单实例对象还是多实例对象

对象地址相同就表明是单例

bean标签的scope用于设置

  • singleton(默认值)单实例

  • prototype多实例

    • 设置为prototype时,不是加载spring配置文件时创建对象,是在调用getBean方法时创建的多实例对象

多实例对象:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd"
        >
    <util:list id="booklist">
        <value>轩辕绝</value>
        <value>完美世界</value>
        <value>悲惨世界</value>
    </util:list>
    <bean id="book" scope="prototype" class="com.wang.pojo.Book">
        <property name="bname" ref="booklist"></property>
    </bean>
</beans>

单实例对象:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd"
        >
    <util:list id="booklist">
        <value>轩辕绝</value>
        <value>完美世界</value>
        <value>悲惨世界</value>
    </util:list>
    <bean id="book" scope="singleton" class="com.wang.pojo.Book">
        <property name="bname" ref="booklist"></property>
    </bean>
</beans>

区别:

Bean的生命周期

  1. 无参构造创建Bean

  2. 为Bean的属性设置值和对其他Bean的使用

  3. 调用bean初始化的方法

  4. bean对象可以使用

  5. 容器关闭--启动bean销毁方法

我们知道对于普通的 Java 对象来说,它们的生命周期就是:

  1. 实例化

  2. 该对象不再被使用时通过垃圾回收机制进行回收

而对于 Spring Bean 的生命周期来说:

  1. 实例化 Instantiation

  2. 属性赋值 Populate

  3. 初始化 Initialization

  4. 销毁 Destruction

通过构造器创建bean实例(无参数构造) 为bean的属性设置值和对其他bean引用(调用set方法) 把bean实例传递给bean后置处理器的方法,postProcessBeforeInitialization 调用bean的初始化的方法(需要进行配置) 把bean实例传递给bean后置处理器的方法,postProcessAfterInitialization bean可以使用了(对象获取到了) 当容器关闭时,调用bean的销毁方法(需要进行配置)

postProcess方法会实现BeanPostProcessor

public class MyBeanPost 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;
}
}

2.9 XML自动装配

根据指定装配规则,Spring自动将匹配的属性值进行注入

<?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="emp" class="com.wang.test.Emp" autowire="byName">
    </bean>
    <bean id="deptFcous" class="com.wang.test.Dept"></bean>
</beans>
package com.wang.test;

public class Emp {
    private String ename;
    public  String gender;
    private Dept deptFcous;

    public void setDept(Dept dept) {
        this.deptFcous = deptFcous;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    public void say(){
        System.out.println("我是"+this.deptFous.getDname()+"的");
    }
}

2.10 IOC操作Bean管理

外部属性文件

  1. 直接配置数据库信息

<?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="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/school"></property>
        <property name="username" value="root"></property>
        <property name="password" value="zhixingheyi0"></property>
    </bean>
</beans>

  1. properties文件读入Spring配置文件

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context">
    <!--引用外部配置文件-->
    <context:property-placeholder location="com.wang:jdbc.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${a.driverclass}"></property>
        <property name="url" value="${a.url}"></property>
        <property name="username" value="${a.username}"></property>
        <property name="password" value="${a.password}"></property>
    </bean>
</beans>

a.driverClass=com.mysql.jdbc.Driver
a.url=jdbc:mysql://localhost:3306/school
a.userName=root
a.password=zhixingheyi0

基于注解方式

使用注解的目的:简化xml配置

Spring针对Bean创建对象的注解:(四类注解功能无区别,不同名称的目的是便于开发)

  1. @Componet

  2. @Service

  3. @Controller

  4. @Repository

基于注解的类对象注入:

  1. 开启组件扫描(告诉Spring容器在哪些类上加上了注解,去扫描这些类所在的包和类)

  2. 在类上加上注解,默认创建该类的对象

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启扫描-->

    <context:component-scan base-package="com.wang.test"></context:component-scan>


</beans>

package com.wang.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Emp {
    private String ename;
    public  String gender;
    //此处必须注解
    //根据属性类型自动装配
    @Autowired
    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;
    }

    public void say(){
        System.out.println("我是"+this.dept.getDname()+"的");
    }
}
package com.wang.test;

import org.springframework.stereotype.Component;

@Component
public class Dept {
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getDname() {
        return dname;
    }
}
package com.wang.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test1 {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Emp emp = context.getBean("emp",Emp.class);
        emp.say();
    }
}

基于注解的属性注入:

  1. @AutoWired 根据属性类型进行自动装配

  2. @Qualifier 根据属性名称注入(与@AutoWired配合使用)

@Autowired  //根据类型进行注入
    @Qualifier(value = "dept")
    private  Dept dept;
   
  1. @Resource 根据类型或名城注入

  2. @Value 注入普通数据类型属性

完全注解开发(实际开发使用Springboot开发)

  1. 创建配置类,替代xml的配置文件

package com.wang;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration //作为配置类,作为xml配置文件
@ComponentScan(basePackages = {"com.wang"})//等价于扫描com.wang包
public class SpringConfig {
    
}
  1. 使用配置类开发

package com.wang.test;

import com.wang.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test1 {
    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Emp emp = context.getBean("emp",Emp.class);
        emp.say();
    }
}

3. AOP

  • 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

  • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

3.1 AOP概念以及原理

3.2 AOP-JDK动态代理

动态代理,通俗点说就是:无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。从而避免了静态代理那样需要声明大量的代理类。

  1. 使用Proxy类里面的方法实现(newProxyInstance)

    1. ClassLoader类加载器

    2. 增强方法所在的类,这个类实现的接口,可以有多个接口

    3. 实现这个接口InvocationHandler,创建代理对象,写增强的方法

动态代理 基本用法:

  1. 定义接口类

package com.wang.Demo001;

public interface UserDao {
    public int add(int a,int b);

    public String update(String id);

}

  1. 实现接口类

package com.wang.Demo001;

public class UserDaoIMPL implements UserDao{
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

  1. 使用动态代理

    1. 调用Proxy.newProxyInstance方法得到接口类的代理对象(传入被代理的对象W)

    2. 实现接口的InvocationHandler,在其中添加增强逻辑

package com.wang.Demo001;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类的对象
        UserDaoIMPL userDaoIMPL = new UserDaoIMPL();
        Class[] interfaces = {UserDao.class};
        UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDaoIMPL));

        System.out.println(userDao.add(1,2));
    }



    static class  UserDaoProxy implements InvocationHandler{
        //传递需要代理的对象
        private Object object;
        //有参构造传递
        public UserDaoProxy(Object obj){
            this.object = 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(object,args);
            //方法之后
            System.out.println("方法之后执行"+object);
            return res;
        }
    }


}

3.3 术语

  1. 连接点:类里面可以被增强的方法

  2. 切入点:实际被增强的方法

  3. 通知(增强):实际增强的逻辑部分

    1. 前置通知(增强的方法之前执行)

    2. 后置通知

    3. 环绕通知

    4. 异常通知(方法出现异常会执行)

    5. 最终通知(finally)

  4. 切面:把通知应用到切入点的过程

3.4 AOP操作

  1. Spring框架一般就是AspectJ实现AOP操作

    • AspectJ不是Spring组成部分,是独立AOP框架,一般把AspectJ和Spring框架一起使用

  2. 基于AspectJ实现AOP操作

    • 基于xml配置文件实现

    • 基于注解实现

  3. 切入点表达式

    • 作用:搞清楚对哪个类的那个方法进行增强

    • 语法结构 :

    • execution([权限修饰符] [返回类型] [类的全路径] [方法名称]([参数列表])

举例:

  1. 对com.wang.dao.BookDao类里面的add进行增强

  • execution(*com.wang.dao.BookDao.add(..))

  1. 对所有方法进行增强

  • execution(*com.wang.dao.BookDao.*(..))

3.5AOP操作(AspectJ注解)

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

package com.wang.AOPAnnotation;

public class User {


    public void add(){
        System.out.println("add....");
    }
}
  1. 创建增强类(编写增强的逻辑)

    1. 在增强类里面创建方法,让不同的方法代表不同通知类型

package com.wang.AOPAnnotation;

public class UserProxy {
    //前置通知
    public void before(){
        System.out.println("befor.......");
    }
}
  1. 进行通知的配置

    1. 在Spring配置文件中,开启注解扫描

      1. <?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:context="http://www.springframework.org/schema/context"
               xmlns:aop="http://www.springframework.org/schema/aop"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                https://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.wang.AOPAnnotation"></context:component-scan>
            
        
        </beans>

    2. 使用注解创建User和UserProxy

      1. package com.wang.AOPAnnotation;
        
        import org.springframework.stereotype.Component;
        
        @Component
        public class UserProxy {
            //前置通知
            public void before(){
                System.out.println("befor.......");
            }
        }
        

    3. 在增强类上添加注解@Aspect

      1. package com.wang.AOPAnnotation;
        
        import org.aspectj.lang.annotation.Aspect;
        import org.springframework.stereotype.Component;
        //增强的类
        @Component
        @Aspect//生成代理对象
        public class UserProxy {
            //前置通知
            public void before(){
                System.out.println("befor.......");
            }
        }
        

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

      1. <!--开启AspectJ生成注解对象,扫描有@Aspect注解的类,有这个注解的就生成代理对象-->
            <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  1. 配置不同类型的通知

    • 在增强类里面,通知方法上面添加通知类型的注解,使用切入点表达式配置

    • 不同类型的通知

package com.wang.AOPAnnotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//增强的类
@Component
@Aspect//生成代理对象
public class UserProxy {
    //切入点
    @Pointcut(value = "execution(* com.wang.AOPAnnotation.User.add())")
    public void pointdemo(){
    }
    //前置通知,在增强方法的前置执行
    @Before(value = "execution(* com.wang.AOPAnnotation.User.add())")
    public void before(){
        System.out.println("before.......");
    }
    //后置通知
    @After(value = "execution(* com.wang.AOPAnnotation.User.add())")
    public void after(){
        System.out.println("after........");
    }
    //在方法两头执行
    @Around(value = "pointdemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前....");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后....");
    }
    //在返回结果之后执行
    @AfterReturning(value = "pointdemo()")
    public void afterReturning(){
        System.out.println("afterreturning");
    }

}
注解 作用 备注
@Before 被增强方法之前
@After 被增强方法之后
@AfterThrowing 异常通知
@AfterReturning 返回结果之后执行
@Around 环绕通知 传入ProceedingJoinPoint参数,早于Before,晚于After
@Pointcut 抽取公共切入点 相当于将多次使用的方法做一个通用空方法代替他
  1. 相同切入点抽取

//    相同切入点抽取
    @Pointcut(value = "execution(* spring5.aopanno.User.add(..))")
    public void pointdemo() {
    }

  1. 有多个增强类对同一个方法进行增强,设置增强类优先级

    • 在增强类上添加注解@Prder,数字越小优先级越高

@Component
@Aspect//生成代理对象
@Order(1)//优先级为1

  1. 完全注解开发,创建配置类,不需要配置xml文件

@Configuration
@ComponentScan(basePackages = {"com.wang"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
// 替代配置文件中的 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
public class ConfigAop {
}
 public void test(){
        // 加载配置类
        ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);
        UserService userService = context.getBean("userService",UserService.class);
        System.out.println(userService);
        userService.add();
    }

3.6 AOP操作(AspectJ配置文件)

4. JdbcTemplate

Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

4.1 概述和准备

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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.wang"></context:component-scan>
    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:JDBC.properties"></context:property-placeholder>
    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${prop.url}"></property>
        <property name="driverClassName" value="${prop.driverClass}"></property>
        <property name="username" value="${prop.username}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>

    <!--JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>



</beans>

prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql:///school
prop.username=root
prop.password=zhixingheyi0

创建Service类,创建Dao类

  • 在dao注入jdbcTemplate对象

  • 在service注入dao对象

package com.wang.JdbcTemplate.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao{
    //注入jdbcTemplate,用它实现数据库的增删改查
    @Autowired
    private JdbcTemplate jdbcTemplate;
}
package com.wang.JdbcTemplate.service;

import com.wang.JdbcTemplate.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    //注入dao
    @Autowired
    private BookDao bookDao;
}

4.2 JdbcTemplate对数据库操作

创建实体类,对应数据库中的表

package com.wang.JdbcTemplate.entity;

public class User {
    private String user_id;
    private String username;
    private String userstatus;

    public String getUser_id() {
        return user_id;
    }

    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUserstatus() {
        return userstatus;
    }

    public void setUserstatus(String userstatus) {
        this.userstatus = userstatus;
    }
}

4.3 添加操作

  • 编写service和dao

    • 在dao进行数据库添加操作

    • 调用JdbcTemplate对象的update方法实现添加操作

package com.wang.JdbcTemplate.dao;

import com.wang.JdbcTemplate.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao{
    //注入jdbcTemplate,用它实现数据库的增删改查
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(User user) {
        String sql = "insert into t_user value(?,?,?)";
        Object[] args = {user.getUser_id(),user.getUsername(),user.getUserstatus()};
        System.out.println(jdbcTemplate.update(sql,args));
    }
}

方法参数:

  • sql语句

  • 可变参数,设置sql语句的值

package com.wang.JdbcTemplate.dao;

import com.wang.JdbcTemplate.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao{
    //注入jdbcTemplate,用它实现数据库的增删改查
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(User user) {
        String sql = "insert into t_user value(1,?,?)";
        Object[] args = {user.getUser_id(),user.getUsername(),user.getUserstatus()};
        System.out.println(jdbcTemplate.update(sql,args));
    }
}

4.4 修改和删除

@Override
    public void updateBook(Book book) {
        //1 创建sql语句
        String sql="update t_book set userName=?,userStatus=? where userId=?";
        //2 调用方法实现
        Object[] args={book.getUserName(),book.getUserStatus(),book.getUserId()};
        int update=jdbcTemplate.update(sql,args);//返回影响的行数
        System.out.println(update);
    }

@Override
    public void delete(String id) {
        //1 创建sql语句
        String sql="delete from t_book where userId=?";
        //2 调用方法实现
        int update=jdbcTemplate.update(sql,id);//返回影响的行数
        System.out.println(update);
    }

4.5 查询

jdbcTemplate.queryForObject(sql,xxx.class);
//第一个参数:sql语句
//第二个参数:返回类型Class

@Override
    public int selectCount() {
        String sql="select count(*) from t_book";
        return jdbcTemplate.queryForObject(sql,Integer.class);
    }

4.6 查询对象和集合

参数一:sql语句 参数二:RowMapper,是接口,返回不同类型数据,使用这个接口里面的实现类完成数据的封装 参数三:sql语句参数值

@Override
    public Book findBookInfo(String id) {
        String sql="select * from t_book where userId=?";
        Book book=jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);
        return book;
    }

@Override
    public List<Book> findAllBook() {
        String sql="select * from t_book";
        List<Book> bookList=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
        return bookList;
    }

4.7 批量操作

批量添加:

参数一:sql语句 参数二:List集合,添加的多条记录数据

//批量添加
    @Override
    public void batchAdd(List<Object[]> batchArgs) {
        String sql="insert into t_book values(?,?,?)";
        int[] arr=jdbcTemplate.batchUpdate(sql,batchArgs);
        System.out.println(Arrays.toString(arr));//影响的行数
    }

//测试
//批量添加
        List<Object[]> batchArgs=new ArrayList<>();
        Object[] o1={"3","java","a"};
        Object[] o2={"4","sql","b"};
        Object[] o3={"5","c++","c"};

        batchArgs.add(o1);
        batchArgs.add(o2);
        batchArgs.add(o3);
        //调用批量添加
        bookService.batchAddBook(batchArgs);

批量修改:

public void batchUpdate(List<Object[]> batchArgs) {
        String sql="update t_book set userName=?,userStatus=? where userId=?";
        int[] arr=jdbcTemplate.batchUpdate(sql,batchArgs);
        System.out.println(Arrays.toString(arr));//影响的行数
    }

//测试
		List<Object[]> batchArgs=new ArrayList<>();
        Object[] o1={"java0909","a3","3"};
        Object[] o2={"sql1212","b4","4"};
        Object[] o3={"c++3434","c5","5"};

        batchArgs.add(o1);
        batchArgs.add(o2);
        batchArgs.add(o3);
        //调用批量添加
        bookService.batchUpdateBook(batchArgs);

批量删除:

public void batchDelete(List<Object[]> batchArgs) {
        String sql="delete from t_book where userId=?";
        int[] arr=jdbcTemplate.batchUpdate(sql,batchArgs);
        System.out.println(Arrays.toString(arr));
    }

5. 事务操作

事务的四个特性:原子性,一致性,隔离性,持久性

1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。

2、一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。

3、隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。

4、持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

5.1 搭建环境

针对转账场景的环境分析:

创建Bank表

设计Dao DaoImpl Service Bank_bean

package com.wang.transaction;

public interface BankDao {
    public void add();
    public void reduce();
}


----------------------------------------------------------------------------------
    package com.wang.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BankDaoImpl implements BankDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add() {
        String sql = "update bank set money=money+? where name=?";
        jdbcTemplate.update(sql,100,"mary");
    }

    @Override
    public void reduce() {
        String sql = "update bank set money=money-? where name=?";
        jdbcTemplate.update(sql,100,"tom");
    }
}
-------------------------------------------------------------------------
    package com.wang.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BankService {
    @Autowired
    private BankDao bankDao;

    public void accountMoney(){
        bankDao.reduce();
        bankDao.add();
    }
}
-----------------------------------------------------------------------------
<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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.wang"></context:component-scan>
    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${prop.url}"></property>
        <property name="driverClassName" value="${prop.driverClass}"></property>
        <property name="username" value="${prop.username}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>

    <!--JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>



</beans>

5.2 事务操作的引入

事务一般添加在service(逻辑业务)层

Spring进行事务管理的操作方式有两种:编程式和声明式(常用)

声明式事务管理:

  • 基于注解(常用)和xml

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

Spring事务管理API:

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

  • PlatformTransactionManager

  1. 开启事务

  2. 业务操作

  3. 无异常提交

  4. 异常回滚

5.3 注解声明式

  1. 配置文件中配置事务管理器

  1. 开启事务注解

引入命名空间tx

<!--开启事务注解-->
    <tx:annotation-driven transaction-manager="tansactionManager"></tx:annotation-driven>
  1. 在service类的方法上添加事务注解

    • 如果添加到类上,则表示此类所有方法都添加事务

@Service
@Transactional
public class BankService {

管理参数配置

propagation(事务传播行为)

(1)Propagation.REQUIRED

如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。

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

  2. 比如有一个事务方法调用了无事务的方法

  3. @Service //@Transactional @Transactional(propagation = Propagation.REQUIRED) public class UserService { }(2)Propagation.SUPPORTS

  4. 如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

  5. (3)Propagation.MANDATORY

    如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

  6. 4)Propagation.REQUIRES_NEW

  7. 重新创建一个新的事务,如果当前存在事务,延缓当前的事务。

  8. (5)Propagation.NOT_SUPPORTED

    以非事务的方式运行,如果当前存在事务,暂停当前的事务。

  9. 6)Propagation.NEVER

  10. 以非事务的方式运行,如果当前存在事务,则抛出异常。

  11. (7)Propagation.NESTED

    如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务。

  12. isolation(事务隔离级别)

    1. 解决事务的隔离性

    2. @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
      
    3. 避免脏读,不可重复读,幻读

  13. timeout(超时时间)

    1. 事务需要在一定时间内提交,否则会进行回滚,默认值是-1,设置时间以秒为单位

  14. readOnly(是否只读)

    1. 默认false,表示CRUD都可以进行

    2. 设置为true后,只能查询

  15. rollbackFor:回滚

    1. 设置查询哪些事务异常需要回滚

  16. noRollbackFor:不回滚

    1. 设置查询哪些事务异常不需要回滚

5.4 xml配置文件方式

  1. 配置事务管理器

  2. 配置通知

  3. 配置切入点和切面

<?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: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
        https://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.wang"></context:component-scan>
    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${prop.url}"></property>
        <property name="driverClassName" value="${prop.driverClass}"></property>
        <property name="username" value="${prop.username}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>

    <!--JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--1.创建事务管理器-->
    <bean id="tansactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--2.配置通知-->
    <tx:advice id="txadvice" >
        <tx:attributes>
            <tx:method name="accountMoney" propagation="REQUIRED"/>
            <!--以count开头的方法都配置
            <tx:method name="acount*"></tx:method>
            -->
        </tx:attributes>
    </tx:advice>
    <!--2.配置切入点和切面-->
    <aop:config >
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.wang.transaction.BankService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut="pt"/>
    </aop:config>


</beans>

5.5 完全注解声明式事务管理

使用配置类替代xml配置文件

package com.wang.config;


import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.activation.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

@Configuration//配置类说明
@ComponentScan(basePackages = "com.wang")//开启扫描
@EnableTransactionManagement//开启事务
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruid() throws IOException {
        DruidDataSource DataSource = new DruidDataSource();
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\jdbc.properties"));
        DataSource.setDriverClassName(properties.getProperty("prop.driverClass"));
        DataSource.setUrl(properties.getProperty("prop.url"));
        DataSource.setUsername(properties.getProperty("prop.username"));
        DataSource.setPassword(properties.getProperty("prop.password"));
        return DataSource;
    }

    //创建Jdbc模板
    @Bean//IOC容器中已经存在DataSource对象,直接声明类型就可以得到该对象
    public JdbcTemplate getJdbcTem(DruidDataSource DataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(DataSource);
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getTransationMan(DruidDataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }



}

--------------------------------------------------------------------------------------
    package com.wang.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class BankService {
    @Autowired
    private BankDao bankDao;

    public void accountMoney(){

        bankDao.add();
        bankDao.reduce();

    }
}

    
  
上一篇:highcharts向下钻取饼图


下一篇:jmeter 非GUI模式下传参