Spring5学习笔记

Spring5学习笔记

1、Spring 概念

  1. Spring 是轻量级的开源的 JavaEE 框架;
  2. Spring 可以解决企业应用开发的复杂性;
  3. Spring 有两个核心部分:IOC 和 Aop
    1. IOC: 控制反转,把创建对象过程交给 Spring 进行管理;
    2. Aop:面向切面,不修改源代码进行功能增强。
  4. Spring 特点:
    1. 方便解耦,简化开发;
    2. Aop 编程支持;
    3. 方便程序测试;
    4. 方便和其他框架进行整合;
    5. 方便进行事务操作;
    6. 降低 API 开发难度。

入门

  1. 下载Spring 选GA稳定版本;

    下载地址

    spring-5.2.6.RELEASE-dist

  2. 打开idea工具,创建普通 Java工程。

  3. 导入 Spring5 相关 jar 包;

spring模块

spring相关jar包

  1. 创建普通的类,创建普通方法

    public class User {
        public void add(){
            System.out.println("add....");
        }
    }
    
  2. 创建 Spring 配置文件,在配置文件配置创建的对象

    1. Spring配置文件使用 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">
    
        <!--配置User对象创建-->
        <bean id="user" class="com.zwj.spring5.User"></bean>
    </beans>
    
  3. 进行测试代码编写

    public class TestSpring5 {
    
        @Test
        public void testAdd() {
            //1 加载spring配置文件
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
    
            //2 获取配置创建的对象
            User user = context.getBean("user", User.class);
    
            System.out.println(user);
            user.add();
        }
    }
    

2、IOC 容器

1、IOC底层原理

1、什么是IOC
  1. 控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理;
  2. 使用IOC 目的:为了耦合度降低;
  3. 上面的入门案例就是 IOC 实现。
2、IOC 底层原理
  1. xml解析、工厂模式、反射
3、图解IOC底层原理

原始模式

工厂模式

IOC过程

如果要修改类路径,只需要修改配置文件即可。【为啥降低了耦合度】

2、IOC接口(BeanFactory)

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

  2. Spring 提供 IOC 容器实现的两种方式:(两个接口)

    • BeanFactory:是spring内部使用的接口,不提供给开发人员进行使用;

      ==特点:==加载配置文件的时候不会创建对象,在获取(使用)对象时才会去创建对象。

    • ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。

      ==特点:==加载配置文件的时候就会把在配置文件里的对象进行创建。

  3. ApplicationContext接口实现类:

ApplicationContext实现类

File的是用于磁盘读取配置文件,Class的是用于工程内部读取的。

3、IOC 操作 Bean 管理(基于xml)

  • 什么是Bean 管理
  1. Spring 创建对象;
  2. Spring 注入属性
1、基于xml方式创建对象

xml配置对象

(1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建;

(2)在 bean 标签有很多属性,介绍常用的属性;

  • id属性:唯一标识;
  • class属性:类全路径(包类路径)

(3)创建对象时候,默认也是执行无参数构造方法完成对象创建。

2、基于 xml 方式注入属性(基础)

(1)DI:依赖注入,就是注入属性;

1、使用 set 方法进行注入
  1. 创建类,定义属性和对应的 set 方法;

    public class Book {
        //创建属性
        private String bname;
        private String bauthor;
        //set方法注入
        public void setBname(String bname) {
            this.bname = bname;
        }
    
        public void setBauthor(String bauthor) {
            this.bauthor = bauthor;
        }
    }
    
  2. 在 spring 配置文件中创建对象,注入属性。

<bean id="book" class="com.zwj.spring5.Book">
    <!--使用property完成属性注入
            name:类里面属性名称
            value:向属性注入值
    -->
    <property name="bname" value="易筋经"></property>
    <property name="bauthor" value="达摩"></property>
</bean>
2、使用有参构造器进行注入

(1)创建类,定义属性和有参构造器;

public class Orders {

    private String oname;
    private String address;

    public Orders(String oname, String address) {
        this.oname = oname;
        this.address = address;
    }
}

(2)在 spring 配置文件中进行配置。

<bean id="orders" class="com.zwj.spring5.Orders">
    <constructor-arg name="oname" value="abc"></constructor-arg>
    <constructor-arg name="address" value="China"></constructor-arg>
</bean>
3、p 名称空间注入

(1)使用 p 名称空间注入,可以简化基于 xml 配置方式;

第一步 添加 p 名称空间在配置文件中:

添加 p 名称空间

第二步 进行属性注入,在bean标签里面进行操作:

<bean id="book" class="com.zwj.spring5.Book" p:bname="九阳神功" p:bauthor="无名氏">
</bean>
3、xml注入其他类型属性
  1. 字面量

    • null 值
    <property name="address">
    	<null/>
    </property>
    
    • 属性值包含特殊符号
    <property name="address">
        <value>
            <![CDATA[<<南京>>]]>
        </value>
    </property>
    
4、注入方式(内部、外部、级联)
1、注入属性-外部 bean

(1)创建两个类 service 类和 dao 类;

(2)在 service 调用 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 add....");
        userDao.update();
    }
}
<bean id="userService" class="com.zwj.spring5.service.UserService">
    <!--
        name属性:类里面属性名称
        ref属性:创建userDao对象bean标签id值
    -->
    <property name="userDao" ref="userDaoImp1"></property>
</bean>
<bean id="userDaoImp1" class="com.zwj.spring5.dao.UserDaoImp1"></bean>
2、注入属性-内部 bean

(1)一对多关系:部门和员工

(2)在实体类中表现一对多关系

//部门类
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;
    }
}

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

<bean id="emp" class="com.zwj.spring5.bean.Emp">
    <!--设置普通属性-->
    <property name="ename" value="lucy"></property>
    <property name="gender" value=""></property>
    <!--设置对象类型属性-->
    <property name="dept">
        <bean id="dept" class="com.zwj.spring5.bean.Dept">
            <property name="dname" value="安保"></property>
        </bean>
    </property>
</bean>
3、注入属性-级联赋值

(1)第一种写法:

<bean id="emp" class="com.zwj.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.zwj.spring5.bean.Dept">
    <property name="dname" value="财务部"></property>
</bean>

(2)第二种写法:需要在emp类中,定义dept的get方法。

<property name="dept.dname" value="技术部"></property>
5、xml注入集合属性

1、注入数组类型属性

2、注入 List集合类型属性

3、注入Map集合属性

(1)创建类,定义数组,list,map,set

public class Stu {
    private String[] courses;
    private List<String> list;
    private Map<String,String> maps;
    private Set<String> sets;
    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
}

(2)spring配置

<bean id="stu" class="com.zwj.spring5.collectiontype.Stu" >
    <property name="courses">
        <array>
            <value>java</value>
            <value>数据库</value>
        </array>
    </property>

    <property name="list">
        <list>
            <value>123</value>
            <value>56</value>
        </list>
    </property>

    <property name="maps">
        <map>
            <entry key="JAVA" value="java"></entry>
            <entry key="PHP" value="php"></entry>
        </map>
    </property>

    <property name="sets">
        <set>
            <value>MySQL</value>
            <value>Redis</value>
        </set>
    </property>
</bean>

4、在集合里面设置对象类型值

<!--创建多个course对象-->
<bean id="course1" class="com.zwj.spring5.collectiontype.Course">
    <property name="cname" value="spring5"></property>
</bean>
<bean id="course2" class="com.zwj.spring5.collectiontype.Course">
    <property name="cname" value="mybatis"></property>
</bean>
<property name="courseList">
    <list>
        <ref bean="course1"></ref>
        <ref bean="course2"></ref>
    </list>
</property>

5、把集合注入部分提取出来

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

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

    
</beans>

(2)使用 util 标签完成 list 集合注入提取

<!--提取list集合类型属性注入-->
<util:list id="bookList">
    <value>易筋经</value>
    <value>九阳神功</value>
    <value>九阴真经</value>
</util:list>
<!--如何使用-->
<bean id="book" class="com.zwj.spring5.collectiontype.Book">
    <property name="list" ref="bookList"></property>
</bean>

2、FactoryBean
  1. Spring 有两种类型bean,一种是普通 bean,里外一种工厂 bean(FactoryBean)

    • 普通 bean:在配置文件中定义 bean 类型就是返回类型;
    • 工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样。
  2. 第一步,创建类,让这个类作为工厂 bean,实现接口 FactoryBean;

    第二步,实现接口里面的方法,在实现的方法中定义返回的 bean 类型。

    public class MyBean implements FactoryBean<Course> {
    
        @Override
        public Course getObject() throws Exception {
            return null;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    
    public class TestSpring5Demo1 {
    
        @Test
        public void test(){
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean2.xml");
            Course course = context.getBean("myBean", Course.class);
            System.out.println(course);
        }
    }
    
    <bean id="myBean" class="com.zwj.spring5.factorybean.MyBean">
    </bean>
    

3、bean 作用域
  1. 在 Spring 里面,设置 bean 实例时单实例还是多实例;

  2. 在 Spring 里面,默认情况下, bean 是单实例对象;

  3. 如何设置单实例还是多实例:

    (1)在 spring 配置文件 bean 标签里面有属性用于设置单实例还是多实例;

    (2)scope 属性值:

    第一个值 默认值,singleton,表示是单实例对象;

    第二个值 prototype,表示是多实例对象。

    <bean id="book" class="com.zwj.spring5.collectiontype.Book" scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>
    

    (3)singletonprototype区别

    1. singleton 单实例, prototype 多实例;

    2. singleton,加载spring 配置文件时候就会创建单实例对象;

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


4、bean生命周期
  1. 通过构造器创建 bean 实例(无参数构造);
  2. 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法);
  3. 调用 bean 的初始化的方法(需要进行配置初始化的方法);
  4. bean 可以使用了(对象获取到了);
  5. 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)。

如果有bean 后置处理器,生命周期变成七步,在第三步的前后都要【把 bean 实例传递 bean 后置处理器的方法】。

5、xml 自动装配
  • 根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入。
<!--实现自动装配
	bean标签属性autowire,配置自动装配;
	autowire属性常用两个值;
		byName根据属性名称注入,注入值bean的id值和类属性名称一样;
		byType根据属性类型注入,在多个同类对象的时候,会出错
-->
<bean id="emp" class="com.zwj.spring5.autowire.Emp" autowire="byName">
</bean>
<bean id="dept" class="com.zwj.spring5.autowire.Dept"></bean>
6、引入外部属性文件
  1. 直接配置数据库信息

    (1)配置德鲁伊连接池;

    (2)引入德鲁伊连接池依赖jar包;

    <!--直接配置连接池-->
    <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/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    
  2. 引入外部属性文件配置数据库连接池

    (1)创建外部配置文件

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

    (2)把外部 properties 属性文件引入到 spring 配置文件中

    • 引入context 名称空间
    <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 http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    • 在 spring 配置文件使用标签引入外部属性文件
    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" 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>
    

4、IOC 操作 Bean 管理(基于注解)

1、优雅初体验
  • 什么是注解
  1. 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
  2. 使用注解,注解作用在类上面,方法上面,属性上面;
  3. 使用注解目的:简化 xml 配置。
  • Spring 针对 Bean 管理中创建对象提供注解
  1. @Component
  2. @Service
  3. @Controller
  4. @Repository

上面四个注解功能是一样的,都可以用来创建 bean 实例

  • 基于注解方式实现对象创建
  1. 引入依赖:aop.jar

  2. 开启组件扫描

    <!--开启组件扫描
        1.如果扫描多个包,多个包使用逗号隔开
        2.扫描包上层目录
    -->
    <context:component-scan base-package="com.zwj"></context:component-scan>
    
  3. 创建类,在类上面添加创建对象注解

    //在注解里面的value属性值可以省略不写
    //默认值是类名称,首字母小写
    @Component(value = "userService") //类似<bean id="" class=""/>
    public class UserService {
    
        public void add(){
            System.out.println("add......");
        }
    }
    
  4. 开启组件扫描细节配置

    <!--
        use-default-filters="false" 表示现在不使用默认filter,自己配置filter
        context:include-filter 设置扫描哪些内容
        下面只扫描@Controller修饰的
    -->
    <context:component-scan base-package="com.zwj" use-default-filters="false">
        <context:include-filter type="annotation"
                          expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
    <!--
        context:exclude-filter 设置哪些内容不扫描
    -->
    <context:component-scan base-package="com.zwj">
        <context:exclude-filter type="annotation"
                          expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
  • 基于注解方式实现属性注入
  1. @AutoWired:根据属性类型进行自动装配;

    • 第一步 把service 和 Dao 对象创建,在service 和 Dao 类添加创建对象注解;
    • 第二步 在service 注入 dao 对象,在 service 类添加 dao 类型;
    @Service
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        public void add(){
            System.out.println("add......");
        }
    }
    
  2. @Qualifier:根据属性名称进行注入;

    这个@Qualifier注解的使用,和上面@AutoWired一起使用

    @Autowired //根据类型进行注入
    @Qualifier(value = "userDaoImp11")//根据名称进行注入
    private UserDao userDao;
    
  3. @Resource:可以根据类型注入,可以根据名称注入;

    本身不建议使用这个,因为调用的库是 javax.annotation.Resource

    //@Resource //根据类型进行注入
    @Resource(value = "userDaoImp11")//根据名称进行注入
    private UserDao userDao;
    
  4. @Value:注入普通类型属性。

    @Value(value = "abc")
    private String name;
    
2、完全注解开发
  1. 创建配置类,替代xml 配置文件;

    @Configuration //作为配置类,替代 xml 配置文件
    @ComponentScan(basePackages = {"com.zwj"})
    public class SpringConfig {
    }
    
  2. 编写测试类

    public class testdemo1 {
    
        @Test
        public void testService(){
            //加载配置类
            AnnotationConfigApplicationContext context =
                    new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = 
                context.getBean("userService",UserService.class);
            System.out.println(userService);
            userService.add();
        }
    }
    

3、Aop

1、概念

  1. 什么是AOP

    1. 面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
    2. 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能;
    3. 使用登录例子说明 AOP

AOP通俗图解

2、底层原理

  1. AOP 底层使用动态代理

    1. 有两种情况动态代理

    第一种 有接口情况,使用 JDK 动态代理

    • 创建接口实现类代理对象,增强类的方法

动态代理接口

第二种 没有接口情况,使用 CGLIB动态代理

  • 创建子类的代理对象,增强类的方法

CGLIB动态代理

3、JDK动态代理

  1. 使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象;

    1. 调用 newProxyInstance 方法

      方法有三个参数:

      (1)类加载器;

      (2)增强方法所在的类,这个类实现的接口,支持多个接口;

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

  2. JDK 动态代理代码

    (1)创建接口,定义方法;

    public interface UserDao {
        public int add(int a,int b);
        public String update(String id);
    }
    

    (2)创建接口实现类,实现方法

    public class UserDaoImp1 implements UserDao{
    
        @Override
        public int add(int a, int b) {
            return a+b;
        }
    
        @Override
        public String update(String id) {
            return id;
        }
    }
    

    (3)使用 Proxy 类创建接口代理对象

    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;
    //            }
    //        });
            UserDaoImp1 userDao = new UserDaoImp1();
            UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int result = dao.add(1, 2);
            System.out.println("result" + 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;
        }
    }
    

4、术语

  1. 连接点

    类里面哪些方法可以被增强,这些方法称为连接点。

  2. 切入点

    实际被真正增强的方法,称为切入点。

  3. 通知(增强)

    (1)实际增强的逻辑部分称为通知(增强);

    (2)通知有多种类型:

    1. 前置通知 @Before
    2. 后置通知 @AfterReturning[返回值之后执行,有异常不执行]
    3. 环绕通知 @Around
    4. 异常通知 @AfterThrowing
    5. 最终通知 @after [不管有没有异常都执行]
  4. 切面

    (1)把通知应用到切入点的过程;


5、准备

  1. spring 框架一般是基于 AspectJ 实现 AOP 操作

    (1)什么是 AspectJ

    • AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spring 框架一起使用,进行 AOP 操作
  2. 基于 Aspect 实现 AOP 操作

    (1)基于 xml 配置文件实现;

    (2)基于注解方式实现(使用)

  3. 在项目工程里面引入 AOP 相关依赖

    下载地址汇总

AspectJjar包

  1. 切入点表达式

    (1)切入点表达式作用,知道对哪个类里面的哪个方法进行增强;

    (2)语法结构:所有用*替代

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


6、AspectJ注解

  1. 创建类,在类里面定义方法;

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

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

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

    (1)在 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"
           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.zwj.spring5.aopanno"></context:component-scan>
    </beans>
    

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

    @Component
    public class UserProxy {
    

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

    @Component
    @Aspect //生成代理对象
    public class UserProxy {
    

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

    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
  4. 配置不同类型的通知

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

    @Component
    @Aspect //生成代理对象
    public class UserProxy {
    
        //前置通知
        @Before(value = "execution(* com.zwj.spring5.aopanno.User.add(..))")
        public void before(){
            System.out.println("before.....");
        }
        
        //环绕通知
        @Around(value = "execution(* com.zwj.spring5.aopanno.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
            System.out.println("环绕之前");
    
            //被增强方法执行
            proceedingJoinPoint.proceed();
    
            System.out.println("环绕之后");
        }
    }
    
  5. 公共切入点抽取 @Pointcut

    //相同切入点抽取
    @Pointcut(value = "execution(* com.zwj.spring5.aopanno.User.add(..))")
    public void pointdemo(){
        
    }
    
    //前置通知
    @Before(value = "pointdemo()")
    public void before(){
        System.out.println("before.....");
    }
    
  6. 有多个增强类使用同一个方法进行增强,设置增强类优先级

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

    @Component
    @Aspect
    @Order(3)
    public class PersonProxy {
    
  7. 完全使用注解开发

    @Configuration
    @ComponentScan(basePackages = {"com.zwj"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop {
    }
    

7、AspectJ 配置文件

  1. 创建两个类,增强类和被增强类,创建方法;

  2. 在Spring 配置文件中创建两个类对象;

    <!--创建对象-->
    <bean id="book" class="com.zwj.spring5.aopxml.Book"></bean>
    <bean id="bookProxy" class="com.zwj.spring5.aopxml.BookProxy"></bean>
    
  3. 在 Spring 配置文件中配置切入点;

    <!--配置Aop增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* com.zwj.spring5.aopxml.Book.buy(..))"/>
    
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <!--增强作用在具体方法-->
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    
    </aop:config>
    

4、JdbcTemplate

1、概念和准备

  1. 什么是 JdbcTemplate

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

  2. 准备工作

    (1)引入相关 jar包;

jdbcTemplate

(2)在spring 配置文件配置数据库连接池;

(3)配置 JdbcTemplate 对象,注入 DataSource;

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

(4)创建 service 类,创建 dao类,在 dao 注入 jdbcTemplate 对象;

  • 配置文件
<!--组件扫描-->
<context:component-scan base-package="com.zwj"></context:component-scan>
  • service
@Service
public class BookService {

    //注入dao
    @Autowired
    private BookDao bookDao;
}
  • dao
@Repository
public class BookDaoImp1 implements BookDao{

    //注入 jdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
}

2、JdbcTemplate操作数据库

1、添加(修改,删除)
  1. 对应数据库创建相应的实体类

  2. 编写 service 和 dao

    (1)在 dao 进行数据库添加操作 jdbcTemplate.update()

    @Repository
    public class BookDaoImp1 implements BookDao {
    
        //注入 jdbcTemplate
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void add(Book book) {
            //sql语句
            String sql = "insert into t_book values(?,?,?)";
            //调用方法实现
            Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};
            int update = jdbcTemplate.update(sql, args);
            System.out.println(update);
        }
    }
    
2、查询
1、查询表记录数

queryForObject(String sql,Class<T> requiredType)第二个参数是返回类型Class

@Override
public int selectCount() {
    String sql="select count(*) from t_book";
    Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
    return count;
}
2、查询返回对象

queryForObject(String sql,RowMapper<T> rowMapper,Object... args)

RowMapper,是接口,返回不同类型数值,使用这个接口里面实现类完成数据封装。

@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;
}
3、查询返回集合

query(String sql,RowMapper<T> rowMapper,Object... args)

@Override
public List<Book> findAllBook() {
    String sql = "select * from t_book";
    List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
    return bookList;
}
3、批量操作
1、批量添加(修改,删除)

batchUpdate(String sql,List<Object[]> batchArgs)

@Override
public void batchAddBook(List<Object[]> batchArgs) {
    String sql = "insert into t_book values(?,?,?)";
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints));
}

5、事务管理

1、搭建事务操作环境(模拟银行)

  1. 创建数据库表,添加表;

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

    (1)service 注入 dao,在 dao 注入 JdbcTemplate,在JdbcTemplate 注入 DataSource;

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

    @Service
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    
        //转账方法
        public void accountMoney(){
            //Lucy少100
            userDao.reduceMoney();
            //Mary多100
            userDao.addMoney();
        }
    }
    
    @Repository
    public class UserDaoImp1 implements UserDao{
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void addMoney() {
            String sql = "update t_account set money=money+? where username=?";
            jdbcTemplate.update(sql,100,"mary");
        }
    
        @Override
        public void reduceMoney() {
            String sql = "update t_account set money=money-? where username=?";
            jdbcTemplate.update(sql,100,"lucy");
        }
    }
    

2、Spring 事务管理介绍

  1. 事务添加到 Service 层(业务逻辑层);

  2. 在Spring 进行事务管理操作:

    (1)有两种方式:编程式事务管理和声明式事务管理(使用)

  3. 声明式事务管理

    (1)基于注解方式;

    (2)基于 xml 配置文件方式。

  4. 在Spring 进行声明式事务管理,底层使用 AOP;

  5. Spring 事务管理 API

    (1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类;

spring事务API类

3、注解声明式事务管理

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

    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  2. 在 spring 配置文件,开启事务注解

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

    <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">
    

    (2)开启事务注解

    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
  3. 在 service 类上面(获取 service 类里面方法上面)添加事务注解

    (1)@Transactional,这个注解添加到类上面,也可以添加方法上面;

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

    (3)如果把这个注解添加到方法上面,为这个方法添加事务。

    @Service
    @Transactional
    public class UserService {
    

4、声明式事务管理参数配置

声明式事务管理配置参数

  1. propagation事务传播行为

    当一个事务方法被另外一个事务方法调用时候,这个事务方法如何进行

7种类传播行为


REQUIRED

required


REQUIRED_NEW:分成外层事务和内层事务
required_new


  1. ioslation事务隔离级别

    (1)事务有特性称为隔离性,多事务操作之间不会产生影响。

    (2)有三个读问题:脏读、不可重复读、幻读

脏读

不可重复读

(3)通过设置隔离级别,解决这些问题。

隔离级别

@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
  1. timeout超时时间

    (1)事务需要在一定时间内进行提交,如果不提交进行回滚;

    (2)默认值时-1,设置时间以秒为单位进行计算。

  2. readOnly是否只读

    (1)读:查询操作;写:添加修改删除操作;

    (2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作;

    (3)设置 readOnly 值时 true,设置成 true 之后,只能查询。

  3. rollbackFor回滚

    (1)设置出现哪些异常进行事务回滚;

  4. noRollbackFor不回滚

    (1)设置出现哪些异常不进行事务回滚;

5、xml 声明式事务管理

  1. 在 spring 配置文件中进行配置;

    第一步 配置事务管理器:

    第二步 配置通知:

    第三步 配置切入点和切面:

        <!--创建事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!--配置通知-->
        <tx:advice id="txadvice">
            <!--配置事务参数-->
            <tx:attributes>
                <!--指定哪种规则的方法上面添加事务-->
                <tx:method name="accountMoney" propagation="REQUIRED"/>
    <!--            <tx:method name="account"/>-->
            </tx:attributes>
        </tx:advice>
        
        <!--配置切入点和切面-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="pt" expression="execution(* com.zwj.spring5.service.UserService.*(..))"/>
            <!--配置切面-->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
        </aop:config>
    

6、完全注解声明式事务管理

  1. 创建配置类,取代xml配置文件;

    @Configuration//配置类
    @ComponentScan(basePackages = "com.zwj")//开启组件扫描
    @EnableTransactionManagement//开启事务
    public class TxConfig {
    
        //创建数据库的连接池
        @Bean
        public DruidDataSource getDruidDataSource(){
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///userDb");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
            return dataSource;
        }
    
        //创建JdbcTemplate对象
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource){
            //到IOC容器中根据类型找到dataSource
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            //注入dataSource
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
        //创建事务管理器对象
        @Bean
        public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
            transactionManager.setDataSource(dataSource);
            return transactionManager;
        }
    }
    

6、Spring5 新特性

整个 Spring5 框架的代码基于Java8,运行时兼容 JDK9,许多不建议使用的类和方法在代码库中删除;

1、Spring5 框架自带了通用的日志封装;

(1)Spring5 已经移除 Log4jConfigListener,官方建议使用 Log4j2;

(2)Spring5 框架整合 Log4j2;

第一步 引入jar包

log4j2jar包

第二步 创建 log4j2.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!--日志级别以及优先级排序:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL-->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration stayus="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

手动测试日志

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserLog {

    private static final Logger log = LoggerFactory.getLogger(UserLog.class);

    public static void main(String[] args) {
        log.info("hello log4j2");
    }
}

2、Spring5 框架核心容器支持@Nullable注解

  1. @Nullable 注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空;

    @Nullable
    String getId();
    
    public void registerBean(@Nullable String beanName){}
    
    @Nullable
    private String bookName;
    

3、Spring5核心容器支持函数式风格GenericApplicationContext

//函数式风格创建对象,交给Spring进行管理
@Test
public void testGenericApplicationContext() {
    //创建GenericApplicationContext
    GenericApplicationContext context = new GenericApplicationContext();
    //调用context的方法对象注册
    context.refresh();
    context.registerBean("user1",User.class, () -> new User());
    //获取在spring注册的对象
    User user = (User)context.getBean("user1");
    System.out.println(user);
}

4、Spring5支持整合 JUnit5

(1)整合 JUnit4

第一步 引入Spring 相关针对测试依赖

spring-test-5.2.6.RELEASE.jar

第二步 创建测试类,使用注解方式完成

@RunWith(SpringJUnit4ClassRunner.class)//指定单元测试的版本
@ContextConfiguration("classpath:bean1.xml")//加载测试文件
public class JTest4 {

    @Autowired
    private UserService userService;

    @Test
    public void test1(){
        userService.accountMoney();
    }
}

(2)Spring5整合 JUnit5

第一步 引入 JUnit5 的 jar 包

第二步 创建测试类,使用注解方式完成

@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean1.xml")
public class JTest5 {

    @Autowired
    private UserService userService;

    @Test
    public void test1() {
        userService.accountMoney();
    }

}

(3)使用一个复合注解替代上面两个注解

@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5 {

    @Autowired
    private UserService userService;

    @Test
    public void test1() {
        userService.accountMoney();
    }

}

Z、想学再学吧

5、SpringWebflux介绍

1、响应式编程
2、Webflux执行流程和核心 API
3、SpringWebflux(基于注解编程模型)
4、SpringWebflux(基于函数式编程模型)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值