JavaSpring框架学习

5 篇文章 0 订阅
Title: JavaSpring框架使用学习
Author: ychhh_


Sping框架的概述

基本概述

在这里插入图片描述

  • 框架概述:

    • javaSpring是轻量级的开源的JavbaEE框架

    • Spring可以解决企业开发的复杂性

    • Spring有两大核心部分:

      1. IOC:控制反转,把创建对象交给Spirng进行管理
      2. Aop:面向切面,不修改源代码的情况下进行功能的增强
  • Spring特点:

    • 方便耦合,简化开发
    • Aop编程支持
    • 方便程序测试
    • 方便和其他框架进行整合
    • 降低API开发难度
spring认识
通过spring创建对象
public class test1 {
    @Test
    public void test(){
        // 加载spring配置文件
        ApplicationContext context =
                new ClassPathXmlApplicationContext("springTest1\\bean1.xml");

        //创建对象
        User user = context.getBean("user",User.class);
        System.out.println(user);
        user.test();
    }

}
  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">
          <!-- 配置对象的创建 -->
          <bean id="user" class="springTest1.User"></bean>
      </beans>
      
  1. 将spring的配置文件引入java文件

    • ApplicationContext context =
                      new ClassPathXmlApplicationContext("springTest1\\bean1.xml");
      
  1. 类的创建

    •  User user = context.getBean("user",User.class);
      

IOC模块

  • IOC底层原理
  • IOC接口(BeanFactory)
  • IOC操作(基于XML / 注解)
概念和原理
  • 什么是IOC
    • 控制反转,把对象的创建和对象之间的调用过程,交给Sring进行处理
    • 使用IOC的目的,为了耦合度的降低
  • IOC的底层原理
    • xml解析,工厂模式,java反射
IOC接口
  • BeanFactory:
    • IOC容器实现的基本接口,不提供给开发人员使用
    • 在加载配置文件时不会创建对象
  • ApplicationContext:
    • BeanFactory接口的子接口,提供更强大的功能
    • 在加载配置文件时就会创建对象
    • 两个基本的实现类:
      1. ClassPathXmlApplicationContext():相对路径(使用ClassLoader加载)
      2. FileSystemPathXmlApplicationContext():绝对路径(使用InputStream加载)
IOC操作Bean管理操作
什么是Bean管理
  • Bean管理指的是两个操作:
    1. Spring创建对象
    2. Spring注入属性
基于xml方式
  • 基于xml的对象构造:

    <bean id="user" class="springTest1.User"></bean> <!-- 默认调用无参构造函数 -->
    
    • 在sprng的配置文件中使用bean标签,标签里添加对应的属性,就可以实现对象的创建
    • 在bean中有很多属性,介绍常用的属性:
      1. id属性:唯一标识
      2. class属性:类的全路径
      3. name属性:可以完成和id属性相同的作用,和id属性唯一的区别为在name属性中可以添加特殊符号,而在id属性中不可以添加特殊符号
    • 默认执行无参构造方法
  • 基于xml的属性注入:

    1. DI:依赖注入,注入属性

      • 第一种注入方式:使用Set方法进行注入

          <bean id="book" class="springTest1.Book">  <!-- 先有对象才有属性 -->
                <property name="bAuthor" value="YCH"></property>
                <property name="bName" value="diao"></property>
            </bean>
        
        public class Book {
        
            public Book(){
        
            }
        
            private String bName;
            private String bAuthor;
        
            public void setbName(String bName) {
                this.bName = bName;
            }
        
            public void setbAuthor(String bAuthor) {
                this.bAuthor = bAuthor;
            }
        
            public String getbName() {
                return bName;
            }
        
            public String getbAuthor() {
                return bAuthor;
            }
        }
        
        
        	@Test
            public void test2(){
                ApplicationContext context = new ClassPathXmlApplicationContext("springTest1\\bean1.xml");
                Book book = context.getBean("book",Book.class);
                System.out.println(book.getbAuthor() + " " + book.getbName());
            }
        
      • 第二中注入方式:使用有参构造方法进行注入

       <!-- 属性注入 (有参构造方式方式)  -->
          <bean id="book1" class="springTest1.Book">
              <constructor-arg name="bAuthor" value="ych"></constructor-arg>
              <constructor-arg name="bName" value="ddd"></constructor-arg>
              <!--
               <constructor-arg index="0" value="ddd"></constructor-arg> 也可以进行属性注入,此时index为有参构造的顺序
      
                     -->
      
          </bean>
      
       @Test
          public void test3(){
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("springTest1\\bean1.xml");
              Book book = context.getBean("book1",Book.class);
              System.out.println(book.getbAuthor());
          }
      
      • Tips:若在一个xml配置文件中既是用了Set方式又使用了有参构造方式,配置文件的id需要为不同的ID
    2. P名称空间注入:

      <!-- 添加xml相关约束(p约束) -->
      <beans xmlns="http://www.springframework.org/schema/beans"
             
             xmlns:p="http://www.springframework.org/schema/p"
             
             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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
          <!-- 配置对象的创建 -->
          <bean id="user" class="springTest1.User"></bean>
      
       @Test
          public void test4(){
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("springTest1\\bean1.xml");
              Book book = context.getBean("book2",Book.class);
              System.out.println(book.getbAuthor());
      
          }
      

    3. 基于xml的其他类型属性注入

      • 属性值为空值:

        <bean id="book3" class="springTest1.Book">
                <property name="bName">
                    <null/>
                </property>
            </bean>
        
      • 属性值中有特殊符号:

        1. 使用转义符:&gt,&lt

        2. 使用CDATA

          <bean id="book4" class="springTest1.Book">
                  <property name="bName" >
                      <value><![CDATA[<<北京>>]]></value>
                  </property>
              </bean>
          
      • 外部注入(属性为类的注入 / 外部bean):

        
            <bean id="service" class="springTest2.UserService.Service">
                <property name="user" ref="user"></property>
            </bean>
        
            <bean id="user" class="springTest2.UserDao.UserDaoImp"></bean>
        
         @Test
            public void test1(){
                ApplicationContext context =
                        new ClassPathXmlApplicationContext("springTest2\\inject.xml");
                UserDao user=  context.getBean("service", Service.class).getUser();
                System.out.println(user);
        
            }
        
      • 内部注入:

        <bean id="emp" class="springTest2.Emp.Emp">
                <property name="name" value="ych"></property>
                <property name="dept">
                    <bean id="dept" class="springTest2.Dept.Dept">
                        <property name="name" value="666"></property>
                    </bean>
        
                </property>
        
        public class Dept {
            private String name;
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getName() {
                return name;
            }
        }
        
        public class Emp {
            Dept dept;
            String name;
        
        
            public void setDept(Dept dept) {
                this.dept = dept;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public Dept getDept() {
                return dept;
            }
        }
        
        
        
      • 级联注入:

        1. 第一种方式和外部注入相似

        2. 给类属性的属性赋值:

          • 前提:需要对属性的主类设置相应属性的get方法
           <bean id="emp2" class="springTest2.Emp.Emp">
                  <property name="dept" ref="dept"></property>
                  <property name="dept.name" value="cs"></property>
              </bean>
              <bean id="dept" class="springTest2.Dept.Dept"></bean>
          
           @Test
              public void test3(){
                  ApplicationContext context =
                          new ClassPathXmlApplicationContext("springTest2\\inject.xml");
                  Emp emp = context.getBean("emp2",Emp.class);
                  System.out.println(emp.getDept().getName());
              }
          
          
          public class Emp {
              Dept dept;
              String name;
          
          
              public void setDept(Dept dept) {
                  this.dept = dept;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public Dept getDept() {
                  return dept;
              }
          }
          
          
      • 集合注入:

         <bean id="stu" class="springTest3.Stu">
                <property name="list">
                   <list>
                       <ref bean="course1"></ref>
                       <ref bean="course2"></ref>
                   </list>
                </property>
                <property name="set">
                    <set>
                        <value>666</value>
                        <value>555</value>
        
                    </set>
        
                </property>
        
                <property name="map">
                    <map>
                        <entry key="java" value="spring"></entry>
                        <entry key="math" value="666"></entry>
                    </map>
                </property>
            </bean>
        
            <bean id="course1" class="springTest3.Course">
                <property name="name" value="ml"></property>
            </bean>
            <bean id="course2" class="springTest3.Course">
                <property name="name" value="db"></property>
            </bean>
        
          @Test
            public void test1(){
                ApplicationContext context =
                        new ClassPathXmlApplicationContext("springTest3\\inject.xml");
                Stu stu = context.getBean("stu",Stu.class);
               for(Course c : stu.list)
                   System.out.println(c.name);
        
               for(String str : stu.map.keySet())
                   System.out.println(str + " " + stu.map.get(str));
            }
        

        Attention:

        • 在类内使用collections的子类时,只能使用最抽象的类(list,set,map)只有这些类在xml有对应的标签

        • 在xml文件中使用对应的标签(list,set,map(entry))

        • 对于一般的字符串型value使用value标签即可进行注入

        • 对于对象型value使用ref,利用类似外部注入的方式进行注入

      • 将类(这里以list为例)公有化:

        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">
        
        
        <util:list id="List">
                <value>666</value>
                <value>777</value>
                <value>888</value>
        
            </util:list>
        
            <bean id="collect" class="springTest3.ListInjecter">
                <property name="list" ref="List"></property>
            </bean>
        
        

        Attention:

        • 需要导入util对应的包:

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

        • 在util:list的标签内,直接添加value(若为String类型的数据)添加id属性

        • 若为对象类的value则利用ref标签引入

        • 在property的标签内,使用ref将公有化的标签的id进行引入

      • 工厂Bean:

        • 使创建的工厂类实现FactoryBean接口(not BeanFactoy)

        • 实现接口内的函数

        • 在getObject的函数内返回要实现的类对象

          public class UserFactory implements FactoryBean<User> {
              @Override
              public User getObject() throws Exception {
                  return new User();
              }
          
              @Override
              public Class<?> getObjectType() {
                  return null;
              }
          
              @Override
              public boolean isSingleton() {
                  return false;
              }
          }
          public class User {
          }
          
          
           <bean id="user" class="springTest4.UserFactory"></bean>
          
      • bean的默认单例性:

        在spring中bean的管理默认为单例模式,即在任何位置使用的bean为同一个bean

        对于bean的单例性的调节:

        • 在xml的配置文件内进行调节
        <bean id="user" class="springTest4.UserFactory" scope="singleton"></bean> <!-- 默认单例 -->
        <bean id="user" class="springTest4.UserFactory" scope="prototype"></bean> <!-- 设置多例 -->
        
        
        • singleton和prototype的区别:
          • 对于默认scope或者指定singleton为在加载xml配置文件时就创建对象
          • 对于指定prototype为在调用getBean函数时才创建对象
      • bean的生命周期

        • 生命周期:从对象创建到销毁的过程

        • bean生命周期(无后置处理器):

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

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

          3. 调用bean的初始化方法(需要配置初始化方法)

          4. bean的使用

          5. 当关闭容器时,需要对bean进行销毁(需要配置销毁方法)

            演示代码:

              <bean id="order" class="springTest5.Order" init-method="initMethod" destroy- method="destroyMethod">
                    <property name="name" value="ych"></property>
                </bean>
            
            
            public class Order {
                private String name;
            
                public void setName(String name) {
                    this.name = name;
                }
            
                private void initMethod(){
                    System.out.println("order has createn!");
                }
            
                private void destroyMethod(){
                    System.out.println("order has destroied!");
                }
            }
            
             @Test
                public void test(){
                    ApplicationContext context =
                            new ClassPathXmlApplicationContext("springTest5\\inject.xml");
                    Order order = context.getBean("order",Order.class);
                    System.out.println("using!");
            		
                    // 销毁创建的bean
                    ((ClassPathXmlApplicationContext)context).close();  //只有ApplicationContext的实现类有close方法
                }
            

            Attention:

            • 当在单例模式下可以用spring进行销毁
            • 当在多例模式下不可用spring进行销毁
        • 有后置处理器:

          • 声明一个实现了BeanPostProcessor的类,并添加值配置文件

          • 在同一个配置文件中的所有bean文件均可调用后置处理器方法:

            public class BeanPostPro implements BeanPostProcessor {
                @Override
                public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                    //  在构造对象之前调用
                    System.out.println("before construct!");
                    return bean;
                }
            
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    
                    //在构造对象之后调用
                    System.out.println("after construct!");
                    return bean;
                }
            }
            
             <bean id="order" class="springTest5.Order" init-method="initMethod" destroy-method="destroyMethod" scope="singleton">
                    <property name="name" value="ych"></property>
                </bean>
            
            
                <bean id="construct" class="springTest5.BeanPostPro"></bean>
            
        • 自动装配(autowire):

          • byName:需要bean的ID和待构造的Bean的属性名相同
          • byType:只能满足“一对一”类型的自动装配
        • 引入配置文件:

          <!-- 引入命名空间 -->
          <?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 http://www.springframework.org/schema/beans/spring-beans.xsd
                 http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
          
          ">
          
          <!-- 引入配置文件 -->
              <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
              
          <!-- 进行属性注入 -->
          	<bean id="jdbc" class="com.alibaba.druid.pool.DruidDataSource">
                  <property name="driverClassName" value="${prop.driverClassName}"></property>
                  <property name="url" value="${prop.url}"></property>
                  <property name="username" value="${prop.username}"></property>
                  <property name="password" value="${prop.password}"></property>
              </bean>
          
          </beans>
          
          • 引入命名空间(context)
          • 引入配置文件
          • 进行属性注入
基于注解方式
  • spring提供的注解:

    1. @Component
    2. @Service
    3. @Controller
    4. @Respository

    ​ * 这四个注解的功能是一样的,都可以用来创建对象

  • 使用注解创建Bean:

    1. 引入aop的jar包,注解的使用需要aop,jar的解释

    2. 在xml中声明需要扫描注解的类(开启组件扫描):

      • 若需要多个类的解决方法:
        1. base-package参数后的类用逗号隔开
        2. 若这多个类在统一目录下,将其父目录加载到base-package中
    3. 在指定类的上方添加注解(Component,Conyroller,Service,Respository之一):

      • 若不添加value属性,则默认value为类名,且类的的一个字母小写,否则为指定的value值
    4. 在创建bean对象时和使用xml创建方法相同

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             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
                                 http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
      
      ">
      
          <context:component-scan base-package="springTest7"></context:component-scan>
      
      </beans>
      
      @Component(value = "user")
      public class User {
          public void start(){
              System.out.println("hello world!");
          }
      }
      
      @Test
          public void test(){
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("springTest7\\scan.xml");
              User user = context.getBean("user",User.class);
              user.start();
          }
      
  • 组件扫描的一些细节:

    • 默认filter:对指定文件中的所有关键词注解进行扫描

    • 指定filter:仅对指定的filter进行扫描 / 不扫描:

          <!-- 指定扫描 -->
      	<context:component-scan base-package="springTest7">
              <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
          </context:component-scan>
      	<!-- 指定不扫描 -->
          <context:component-scan base-package="springTest7" use-default-filters="false">
              <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
          </context:component-scan>
      
      * **当为指定扫描时,需要将默认扫描(use-default-filters)改为false**
      * **当为指定不扫描时,无需设置**
      
  • 基于注解方式的属性注入:

    • 常用注解:

      1. @AutoWire:根据属性的类型进行自动注入
      2. @Qualifier:根据属性的名称进行注入
      3. @Resource:既可以根据类型注入也可以根据名称进行注入
      4. @Value:普通类型的注入
    • AutoWire:

      • 按照类型进行注入,直接在指定属性上添加该注解即可(只能当指定的类型只存在一个时,当存在多个候选的类型时不能使用该方法进行属性注入)
    • Qualifier:

      • 按照名称进行注入

      • 使用Qualifier时必须在其上添加AutoWire注解,即两个注解同时使用

        	@Autowired  // 必须先添加AutoWire注解,若无该注解则无法使用Qualifier
            @Qualifier(value = "user")
            private UserDao user;
        
    • Resource:

      • 既可以根据类型进行注入,也可以根据指定的名称进行注入。
      • 不是Spring包中的功能,是javax中的annoation的
      • Spring不推荐
    • Value:

      • 注入普通类型(非特殊对象类注入)
  • 完全注解开发:

    • 完全使用注解进行开发,完全不使用xml

    • 步骤:

      1. 创建配置类并添加配置注解

      2. 加载配置类

      3. 创建bean对象

        // 注解类
        @Configuration
        @ComponentScan(basePackages = {"springTest9"})
        public class Config {
        }
        
        
        @Repository
        public class User implements UserDao{
            @Override
            public void show() {
                System.out.println("666");
            }
        }
        
        
        @Service
        public class UserService {
        
            @Autowired
            private UserDao user;
        
            public void show(){
                user.show();
                System.out.println("777");
            }
        }
        
        
            @Test
            public void test(){
                ApplicationContext context =
                        new AnnotationConfigApplicationContext(Config.class); // 此处改为Annotation的子实现类
                UserService user = context.getBean("userService",UserService.class);
                user.show();
            }
        

AOP模块

AOP基本概念
  • 作用:使用AOP思想,可以使业务逻辑部分进行隔离,使业务逻辑的耦合度降低,提高了代码重用性,提升了开发效率

  • 通俗说明:不通过修改源代码的方式修改程序的主干

  • 底层原理:AOP底层使用动态代理:

    • 两种情况的动态代理:
      1. 有接口的情况,使用JDK的动态代理
      2. 无接口的情况,使用CGLIB的动态代理
  • 术语:

    • 连接点:

      类中哪些方法可以被增强,哪些方法就称为连接点(候选方法)

    • 切入点

      类内实际被增强的方法称为切入点(实际增强方法)

    • 通知(增强)

      1. 实际增强的逻辑部分被称为通知(增强)
      2. 通知有很多类型:
        • 前置通知
        • 后置通知
        • 环绕通知
        • 异常通知(exception)
        • 最终通知(finally)
    • 切面

      把通知应用到切入点的过程称为切面

JDK动态代理
Class Proxy
  • from:Java.lang.reflect.Proxy

  • some methods:

    • static Obcejct newProxyInstance(ClassLoader loader,类<?>[] interfaces ,InvocaionHandler h):

      parameters:

      1. loader:类加载器
      2. interfaces:增强方法所在的类,这个类实现的接口,该接口可以为多个接口
      3. h(InvocationHandler):实现Invocatiion的接口,创建代理的对象,实现对象增强的部分
      public class JDKProxy {
          public static void main(String[] args) {
              Class []interfaces = {UserDao.class};
      
              UserDao user = new UserDaoImpl();
      
              UserDao user1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
                  private Object obj = user;
      
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                      System.out.println("hello");
                      Object res = method.invoke(obj,args);
                      System.out.println("world");
                      return new Integer(6);
      
                  }
              });
      
              System.out.println(user1.intInter(1,2));
      
          }
      }
      
      
AOP操作(准备)
  • Spring框架一般是基于AspectJ实现的AOP操作:

    • 什么是AspectJ:

      AspectJ不是Spring的组成部分,独立的AOP框架,一般把AspectJ和Spring一起使用,进行AOP操作

    • 基于AspectJ实现AOP操作

  • 切入点表达式:

    • 切入点表达式的作用:知到对类内的哪个方法进行增强

    • 语法结构:

      execution(【权限修饰符】【返回类型】【类全路径】【方法名称】(【参数列表】))

    • 举例说明:

      说明:

      • *代表所有的权限
      • 返回类型可以省略
      • .*代表其中的所有
      • 参数列表用…进行代替
      1. 对指定类的指定方法做增强:

        excution(* spirngTest8.User,add(…))

      2. 对指定类的所有方法做增强:

        excution(* sprintTest8.User.*(…))

      3. 对指定包的所有类的所有方法做增强:

        excution(* springTest8..(…))

基于注解的AspectJ的AOP操作(推荐使用方法)
  • 使用xml文件进行配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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
                                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="sprintTest12"></context:component-scan>
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
    
    </beans>
    
  • 使用配置类进行AOP操作

    
    @Configuration
    @ComponentScan(basePackageClasses = {Order.class, OrderPorxy.class})
    @EnableAspectJAutoProxy(proxyTargetClass = true) // 进行AOP配置
    public class Config {
    }
    
    
  • 配置Proxy类

    @Component
    @Aspect //声明为AOP切口代理 
    public class OrderProxy {
    
        @Before(value = "execution(* sprintTest12.Order.add(..))")
        void before(){
            System.out.println("world");
        }
    }
    
  • ATTENTION:

    在进行aop的引入时,需要将proxy-target-class声明为TRUE

    <tx:annotation-driven transaction-manager=“transactionManager”
    proxy-target-class=“true”/>
      注意:proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为false,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为true,那么标准的JDK 基于接口的代理将起作用。

    即使你未声明 proxy-target-class=“true” ,但运行类没有继承接口,spring也会自动使用CGLIB代理。

    高版本spring自动根据运行类选择 JDK 或 CGLIB 代理

  • 执行顺序:

    无异常情况:

    ​ around before…

    ​ before
    Method
    ​ around after
    ​ after…
    ​ after returning…

    有异常情况:

    ​ around before…

    ​ before
    ​ after…
    ​ throwing

  • 综上总结:

    • @before 前置通知
    • @after 最终通知
    • @afterReturning 后置通知
    • @around 环绕通知
    • @afterThrowing 异常通知
  • 相同切入点抽取:

    • 对相同的execution进行抽取,并合并使用

    • 方法:

      1. 构建切入点函数

      2. 填充

         	@Pointcut(value = "execution(* springTest13.Order.show(..))") // 构切入点函数
            void pointCutDemo(){}
        
            // 利用切入点函数进行填充
        
        	@Before(value = "pointCutDemo()")
            void before(){
                System.out.println("before");
            }
        
        
            @After(value = "pointCutDemo()")
            void after(){
                System.out.println("after..");
            }
        
            @AfterReturning(value = "pointCutDemo()")
            void afterReturning(){
                System.out.println("after returning..");
            }
        
            @Around(value = "pointCutDemo()")
            void round(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
                System.out.println("around before..");
                proceedingJoinPoint.proceed();
                System.out.println("around after");
            }
        
            @AfterThrowing(value = "pointCutDemo()")
            void afterThrow(){
                System.out.println("throwing");
            }
        
        
  • 如果一个切入点使用多个代理的增强方法,如需要自定义设置增强的先后顺序,则在代理类的上增加主机注解 — @Order(value = 1…)

    • 若value的值越小则优先级越高
  • 完全注解开发:

    
    
    @Configuration
    @ComponentScan(basePackageClasses = {Order.class, OrderPorxy.class})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class Config {
    }
    
    
基于xml文件的AspectJ的配置方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
                            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
">

    <bean id="user" class="springTest12.UserDaoImpl"></bean>
    <bean id="userProxy" class="springTest12.UserProxy"></bean>

    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

    <aop:config>
        <aop:pointcut id="p" expression="execution(* springTest12.UserDao.show(..))"/>

        <aop:aspect ref="userProxy" order="1">
            <aop:before method="before" pointcut-ref="p" ></aop:before>

        </aop:aspect>


    </aop:config>

</beans>

JDBCTemplate模块

JDBCTemplate基本概念
  • 什么是JDBCTemplate:Spring对JDBC进行了封装,使用JDBCTemplate方便对数据库进行操作
  • 添加相关依赖jar包
JDBCTemplate相关配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/aop"
       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
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

">

    <context:component-scan base-package="springTest14"></context:component-scan>

   <util:properties id="prop" location="jdbc.properties" local-override="true"></util:properties>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="#{prop.driverClassName}"></property>
        <property name="url" value="#{prop.url}"></property>
        <property name="username" value="#{prop.username}"></property>
        <property name="password" value="#{prop.password}"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>

    </bean>

</beans>
  • 对于其余部分为:

    JDBCTemplate -> Dao -> Service

  • tips:针对MYSQL的URL形式

    jdbc:mysql://localhost:/

利用JDBCTemplate进行(增删改)操作
@Component
public class CustoemrDaoImpl implements  CustomerDao{


    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public void add(Customer cus) {
        String sql = "insert into customers (id,name,email) values (?,?,?);";
        int update = jdbcTemplate.update(sql,cus.getId(),cus.getName(),cus.getEmail());
        System.out.println(update);
    }
}

//`id``name``email``birth``photo``test`
public class Customer {
    private int id;
    private String name;
    private String email;
    private String birth;
    private String photo;
    private String test;

    public Customer(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }



    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getBirth() {
        return birth;
    }

    public String getPhoto() {
        return photo;
    }

    public String getTest() {
        return test;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setBirth(String birth) {
        this.birth = birth;
    }

    public void setPhoto(String photo) {
        this.photo = photo;
    }

    public void setTest(String test) {
        this.test = test;
    }
}

public interface CustomerDao {

    void add(Customer cus);
}


@Component
public class Service {

    @Autowired
    private CustomerDao customer;

    public void addCustomer(Customer cus){
        customer.add(cus);
    }




}

 @Test
    public void test(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("springTest14\\config.xml");
        Service s = context.getBean("service",Service.class);
        s.addCustomer(new Customer(1234,"ych","132@"));

    }
利用JDBCTemplated对数据库进行查询操作
  • 实现集合函数的查询

    利用JDBCTemplate封装的queyForObject函数,返回单个值

    • 参数解析:
      • 第一个参数:sql语句
      • 第二个参数:返回的对象类型的class
    @Override
        public void selectSet(Customer cus) {
            String sql = "select count(*) from customers";
            Integer res = jdbcTemplate.queryForObject(sql,Integer.class);
            System.out.println(res);
        }
    
  • 实现单一对象的查询

    • 参数解析:
      • 第一个参数:sql语句
      • 第二个参数:
        • 实现类RowMapper的接口的类(ex:BeanPropertyRowMapper)
        • 模板类别为数据库返回类型的类别
      • 第三个参数:填充参数
    • 此方法的返回结果为一个查询的实现类
     @Override
        public void getTuple(String name) {
            String sql = "select * from customers where name=?;";
            Customer cus = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Customer>(Customer.class),name);
            System.out.println(cus.getName());
       }
    
  • 实现对集合的查询

    • quert参数解析

      • 第一个参数:sql语句
      • 第二个参数:RowMapper的接口实现类
      • 第三个参数:填充字符
    • 使用list进行容纳

     @Override
        public void findTuples() {
            String sql = "select * from customers;";
            List<Customer> customerList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Customer>(Customer.class));
            for(Customer cus : customerList)
                System.out.println(cus.getName());
        }
    
利用JDBCTemplate实现批量操作
  • 批量增加

    一个Object数组对象为一个元组,一个Objecr对象为一个属性

    	@Override
        public void addBatch(List<Object[]> list) {
            String sql = "insert into customers (id) values (?);";
            int res[] = jdbcTemplate.batchUpdate(sql,list);
            System.out.println(Arrays.toString(res));
        }
    
  • 删改同理

利用JBDCTemplate实现事物管理
  • 什么是事物:

    事物是数据库操作的基本单元,逻辑上的一组操作

  • 事物的基本性质(ACID):

    • 原子性
    • 一致性
    • 分离性
    • 持久性
  • Attention:

    • 事物一般添加到Service层(WEB层,Service层,Dao层)
  • 事物管理的一般方法:

    • 编程式事物管理(不推荐)
    • 声明式事物管理**(底层使用了AOP的模式)**:
      1. xml方式
      2. 注解方式
基于注解的事务管理
  • 实现方法:

    • 引入tx的命名空间

    • 声明事物控制器的bean模块,并注入dataSource

    • 通过事物控制器打开注解驱动

    • 在事物类上或事物的方法上添加事物注解

      <?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:tx="http://www.springframework.org/schema/tx"
            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/context  http://www.springframework.org/schema/context/spring-context.xsd
                                     http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util.xsd
                                     http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx.xsd
      
      ">
          <context:component-scan base-package="springTest15"></context:component-scan>
          <util:properties id="prop" local-override="true" location="jdbc.properties"></util:properties>
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="url" value="#{prop.url}"></property>
              <property name="username" value="#{prop.username}"></property>
              <property name="password" value="#{prop.password}"></property>
              <property name="driverClassName" value="#{prop.driverClassName}"></property>
          </bean>
      
          <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
              <property name="dataSource" ref="dataSource"></property>
          </bean>
      /
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <property name="dataSource" ref="dataSource"></property>
          </bean>
          <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
      
      </beans>
      <!--
      
      
      url=jdbc:mysql://localhost:3307/test
      username=root
      password=ych3362632
      driverClassName=com.mysql.jdbc.Driver
      
      
      -->
      
      @Component
      @Transactional
      public class UserService {
          @Autowired
          private UserDao customer;
      
          private void addMoney(String name,int m){
              customer.addMoney(name,m);
          }
      
          private void relasMoney(String name,int m){
              customer.relasMoney(name,m);
      
          }
      
          public void getPostMoney(String name1,String name2,int m){
              addMoney(name2,m);
              int e = 10 / 0;
              relasMoney(name1,m);
      
          }
      
      }
      
      
  • 声明式事物管理参数配置

    • propgation:传播行为

    • ioslation:事物的隔离级别:

      1. 【错误】脏读:一个未提交的事物读取了另一个未提交的事物(当被读的事物发生了rollback则导致数据不正确)

      2. 【现象非问题】幻读:一个未提交的事物读取了另一个事物添加的数据

      3. 【现象非问题】不可重复读:一个未提交的事物读取了另一个事物已经提交的数据

      设置隔离级别:

      脏读不可重复读幻读
      READ UNCOMMITTED(读未提交)
      READ COMMITTED(读已提交)×
      REPEATABLE READ(可重复读)【MySQL默认】××
      SERILIZABLE(串行化)×××
    • timeout:超时时间:

      1. 事物需要在一定的时间内进行提交,如果不提交则进行回滚
      2. 默认值-1(不超时),设置时间以秒为单位
    • readOnly:是否只读:

      1. readOnly默认值为false,可进行增删改查
      2. 若设置为true,则只能查询
    • rollbackFor:设置出现哪些异常进行回滚

    • noRollbackFor:设置出现哪些异常不进行回滚

基于xml的事物管理
  • 基于xml文件的配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:util="http://www.springframework.org/schema/util"
           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
                         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                         http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
                         http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util.xsd
                         http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx.xsd
    
    
    ">
        <util:properties id="prop" location="jdbc.properties" local-override="true"></util:properties>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="#{prop.url}"></property>
            <property name="driverClassName" value="#{prop.driverClassName}"></property>
            <property name="password" value="#{prop.password}"></property>
            <property name="username" value="#{prop.username}"></property>
        </bean>
    
        <context:component-scan base-package="springTest16"></context:component-scan>
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <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="getPostMoney" propagation="REQUIRED"/>
            </tx:attributes>
    
        </tx:advice>
    
        <aop:config>
            <aop:pointcut id="pt" expression="execution(* springTest16.UserService.getPostMoney(..))"/>
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
        </aop:config>
    
    </beans>
    
完全注解开发
  • 步骤:

    • 创建配置类
    • 填充配置函数
    • 完成配置
    
    @Configuration
    @ComponentScan(basePackages = {"springTest17"})
    @EnableTransactionManagement
    public class Config {
    
        @Bean
        public DruidDataSource getDataSource(){
            DruidDataSource dataSource = new DruidDataSource();
            Properties prop = new Properties();
            FileInputStream fis = null;
            try {
                fis = new FileInputStream("src\\jdbc.properties");
                prop.load(fis);
                dataSource.setUrl(prop.getProperty("url"));
                dataSource.setUsername(prop.getProperty("username"));
                dataSource.setPassword(prop.getProperty("password"));
                dataSource.setDriverClassName(prop.getProperty("driverClassName"));
    
    
    
    
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return dataSource;
            }
    
    
        }
    
    
        @Bean
        public JdbcTemplate getJdbcTemplate(){
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(getDataSource());
            return jdbcTemplate;
        }
    
        @Bean
        public DataSourceTransactionManager getDataSourceTransactionManager(){
            DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
            dataSourceTransactionManager.setDataSource(getDataSource());
            return dataSourceTransactionManager;
        }
    
    }
    
    
    
    @Component
    public class UserDaoImpl implements UserDao{
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void show() {
            String sql = "select * from customers;";
            List<User> list = jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class));
            for(User user : list)
                System.out.println(user.getName());
        }
    }
    
    


补充

工厂模式

普通模式:

class UserService{
    public void execute(){
        User user = new User();
        user.add();
    }
}
class UserDao{
    public void add(){
        System.out.println("hello world!");
    }
}
/*
该模式缺点:
	UserService和User类的耦合度太高
	需要利用工厂模式进行解耦合

*/

工厂模式:

class UserService{
    public void execute(){
        User user = UserFactory.getUserDao();
        user.add();
    }
}
//UserFatory使用工厂模式降低UserService和UserDao的耦合度
class UserFactory{
    public static getUserDao(){
        return new UserDao();
    }
}

class UserDao{
    public void add(){
        System.out.println("hello world!");
    }
}

/*
 通过工厂模式,使得UserService和User的耦合度进一步降低(但是并未降到最低)
 另外UserFactory和User的耦合度依然很高

*/

在工厂模式的情况下进一步解耦合

//利用反射进一步解耦合
class UserFactory{
    public static UserDao getUserDao(){
        String classValue = class属性值; //通过xml解析得到
        Class clazz = Clazz.forName(classValue);
        return (UserDao)clazz.newInstance();
    }
}

注解

  • 注解是代码的特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
  • 使用注解,注解作用在类上,方法上,属性上
  • 使用注解的目的(在spring中),简化xml文件的配置

动态代理

  1. 有接口的动态代理(JDK动态代理)

    • 通过实现接口类的方法来增强类的对象

在这里插入图片描述

  1. 无接口的动态代理(CGLIB动态代理)

    • 通过实现子类的方法来增强类

      在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值