Spring学习笔记

Spring 学习

狂神笔记

知识点

  1. 简介

    1. Spring依赖包
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.3.RELEASE</version>
    </dependency>
     ```
    
  2. IOC理论

    1. 控制反转(IOC) 面向切面变成(AOP)
    2. 传统的MVC模式
      1. UserDao
      2. USerDaoImpl
      3. UserService
      4. UserServiceImpl

    在此之前,用户需求可能会影响原来的代码

    在UserServiceImpl里面 设置private UserDao user;
    通过使用set,则可以根据用户需求选择,而不用改变原来的代码

    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    
    • 之前是主动创建对象,控制权在程序员手上
    • 使用set之后,是被动接受对象
  3. Hello Spring

    • resource中 beans.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 = 变量名-->
        <!--class = new的对象-->
        <!--property 相当于给对象中的属性设值-->
        
        <bean id="hello" class="com.hou.pojo.Hello">
            <property name="name" value="Spring"/>
        </bean>
    </beans>
    
    • test中
     import com.hou.pojo.Hello;
     import org.springframework.context.ApplicationContext;
     import org.springframework.context.support.ClassPathXmlApplicationContext;
     
     public class Mytest {
     
         public static void main(String[] args) {
             //获取spring上下文对象
             ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
             //我们的对象下能在都在spring·中管理了,我们要使用,直接取出来就可以了
             Hello hello = (Hello) context.getBean("hello");
             System.out.println(hello.toString());
         }
     }
    
    • 涉及知识点:
      • bean = 对象
      • id = 变量名
      • class = 类
      • property 相当于给对象设置属性
      • 核心为 set 注入
      • UserServerImpl中存在UserDao属性,则这个时候需要使用 ref
      <?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="userdaomysql" class="com.hou.dao.UserDaoMysqlImpl"></bean>
      
          <bean id="userServiceImpl" class="com.hou.service.UserServiceImp">
              <!--ref引用spring中已经创建很好的对象-->
              <!--value是一个具体的值-->
              <property name="userDao" ref="userdaomysql"/>
          </bean>
      
      </beans>
      
  4. IOC创建对象的方式

    1. 使用无参构造创建对象,默认
    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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              https://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <bean id="user" class="com.hou.pojo.User">
              <constructor-arg index="0" value="hou"/>
          </bean>
      </beans>
      
    • 类型赋值

      <bean id="user" class="com.hou.pojo.User">
          <constructor-arg type="java.lang.String" value="dong"/>
      </bean>
      
    • 直接通过参数值

      <bean id="user" class="com.hou.pojo.User">
          <constructor-arg name="name" value="hou"></constructor-arg>
      </bean>
      
    • 知识点

      IOC创建对象的方式,在这里 Spring类似于婚介网站,不管你想不想要,对象都在里面。

  5. Spring 配置

    1. 别名:使用 <alias />

      <bean id="user" class="com.hou.pojo.User">
          <constructor-arg name="name" value="hou"></constructor-arg>
      </bean>
      <alias name="user" alias="user2aaa"/>
      
    2. Bean的配置

      • id: bean的id标识符
      • class: bean对象所在的类型
      • name:别名,可以同时取多个别名
    3. import

      将多个配置文件,导入合并成一个
      <import resource="beans.xml"/>

  6. DI依赖注入

    1. 注入方式

      构造器注入 一定要有一个无参构造

      set方式注入(重点)

      • 依赖:bean对象的创建依赖于容器
      • 注入: bean对象中的所有属性,由容器来注入
    2. 常用的数据类型

      Student.java

          private String name;
          private Address address;
      
          private String[] books;
          private List<String> hobbies;
      
          private Map<String, String> card;
          private Set<String> game;
      
          private Properties infor;
          private String wife;
      

      Address.java

      public class Address {
          private String address;
      
          public String getAddress() {
              return address;
          }
      
          public void setAddress(String address) {
              this.address = address;
          }
      
          @Override
          public String toString() {
              return "Address{" +
                      "address='" + address + '\'' +
                      '}';
          }
      }
      

      beans.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="address" class="com.pojo.Address">
              <property name="address" value="xian"></property>
          </bean>
      
          <bean id="student" class="com.pojo.Student">
              <property name="name" value="hou"/>
              <property name="address" ref="address"/>
      
              <!--数组注入-->
              <property name="books">
                  <array>
                      <value>三国</value>
                      <value>西游</value>
                      <value>水浒</value>
                  </array>
              </property>
      
              <!--list-->
              <property name="hobbies">
                  <list>
                      <value>eat</value>
                      <value>drink</value>
                      <value>play</value>
                  </list>
              </property>
      
              <property name="card">
                  <map>
                      <entry key="1" value="12"/>
                      <entry key="2" value="23"/>
                  </map>
              </property>
      
              <property name="game">
                  <set>
                      <value>wangzhe</value>
                      <value>daota</value>
                      <value>lol</value>
                  </set>
              </property>
      
              <property name="wife">
                  <null></null>
              </property>
      
              <!--properties-->
              <property name="infor">
                  <props>
                      <prop key="id">20200405</prop>
                      <prop key="name">hdk</prop>
                  </props>
              </property>
          </bean>
      
      </beans>
      
    3. 知识点

      • property里的name 对应 Address.java里面的address

         <bean id="address" class="com.pojo.Address">
             <property name="address" value="xian"></property>
         </bean>
         ```
        
      • <null/>赋值,赋null值,其效果跟 ex.setvalue(null) 效果一样;
        注意 “ ”与null的区别

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-90oEPih1-1598271535913)(image/empty_Null_1.png)]
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i01ztWoh-1598271535934)(image/empty_Null_2.png)]

    4. 第三方 p标签 和 c标签

      • 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"
               xmlns:p="http://www.springframework.org/schema/p"
               xmlns:c="http://www.springframework.org/schema/c"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                https://www.springframework.org/schema/beans/spring-beans.xsd">
        
            <!--p命名空间注入/set注入-->
            <bean id="use" class="com.pojo.User" p:name="dong" p:age="10">
            </bean>
        
            <!--c命名空间/构造器-->
            <bean id="use2" class="com.pojo.User" c:name="kun" c:age="19"></bean>
        </beans>
        
      • 知识点

        1. p命名空间是使用 set注入
        2. c命名空间是使用 构造器
    5. bean的作用域

      • 单例模式(默认)不管id有多少个,只要class是一样的,都只有一个对象

        <bean id="use2" class="com.pojo.User" c:name="kun" c:age="19" scope="singleton"></bean>

      • 原型模式:每次从容器中get的时候,都产生一个新对象

        <bean id="use2" class="com.pojo.User" c:name="kun" c:age="19" scope="prototype"></bean>

      • 其余的request,session,application这些只能在web开放中使用。

  7. Bean的自动装配

    1. Spring有三种装配方式

      1. 在xml中显示配置
      2. 在java中显示配置
      3. 隐式的自动装配bean【important
        1. 环境搭建:一个人有两个宠物

        2. Byname自动装配:byname会自动查找,和自己对象set对应的值对应的id,保证所有
          id唯一,并且和set注入的值一致。

          1. 看例子

            <bean id="cat" class="pojo.Cat"/>
                <bean id = "dog" class="pojo.Dog"/>
                <!--byname自动查找,和自己对象set对应的值对应的id-->
                <bean id="people" class="pojo.People" autowire="byName">
                    <property name="name" value="sha"></property>
                </bean>
            

            test code: people.getCat().shout();

          2. 而如果是将id改了,即id=“cat123”,则查找不到

            <bean id="cat123" class="pojo.Cat"/>
                <bean id = "dog" class="pojo.Dog"/>
                <!--byname自动查找,和自己对象set对应的值对应的id-->
                <bean id="people" class="pojo.People" autowire="byName">
                    <property name="name" value="sha"></property>
                </bean>
            
          3. 以前的话,需要使用ref

                 <bean id="userdaomysql" class="com.hou.dao.UserDaoMysqlImpl"></bean>
                 
                     <bean id="userServiceImpl" class="com.hou.service.UserServiceImp">
                         <!--ref引用spring中已经创建很好的对象-->
                         <!--value是一个具体的值-->
                         <property name="userDao" ref="userdaomysql"/>
                      </bean>
            
        3. Bytype 自动装配:bytype会自动查找,和自己对象属性相同的bean,保证所有的class唯一。

          1. 跟byname差不多,直接看代码
            <?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="cat11" class="com.pojo.Cat"/>
                <bean id="dog" class="com.pojo.Dog"/>
                <!--byname会自动查找,和自己对象set对应的值对应的id-->
                <!--<bean id="people" class="com.pojo.People" autowire="byName">-->
                    <!--<property name="name" value="hou"></property>-->
                <!--</bean>-->
                <!--byType会自动查找,和自己对象属性相同的bean-->
                <bean id="people" class="com.pojo.People" autowire="byType">
                    <property name="name" value="hou"></property>
                </bean>
            
            </beans>
            
    2. 使用注解自动装配

      1. jdk1.5支持的注解,spring2.5支持的注解

      2. 导入context约束

        <?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
                https://www.springframework.org/schema/context/spring-context.xsd">
        
            <context:annotation-config/>
        
        </beans>
        
      3. @Autowire

        在属性上使用,也可以在set上使用

        可以不用编写set方法了

        public class People {
            @Autowired
            private Cat cat;
            @Autowired
            private Dog dog;
            private String name;
        }
        

      @Nullable 字段标志的注解,说明这个字段可以为null

    3. 如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候

      我们可以使用@Qualifier(value = “dog”)去配合使用,指定一个唯一的id对象

      (也就是说,如果自动装配没有找到相应的id,则使用@Qualifier给的默认值)

      public class People {
          @Autowired
          private Cat cat;
          @Autowired
          @Qualifier(value = "dog")
          private Dog dog;
          private String name;
      }
      

      当然,@Resource(name=“dog”)也可以

      区别:

      • @autowire通过byType实现,而且必须要求这个对象存在
      • @resource默认通过byName实现,如果找不到,通过byType实现
  8. 使用注解开发

    1. spring4之后,必须保证aop包的导入

      <?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
              https://www.springframework.org/schema/context/spring-context.xsd">
      
          <context:annotation-config/>
      
      </beans>
      
    2. 属性注入

      @Component
      public class User {
          
          @Value("dong")
          private String name;
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      }
      
    3. 衍生的注解

      @Component有几个衍生注解,会按照web开发中,mvc架构中分层。

      • dao (@Repository)
      • service(@Service)
      • controller(@Controller)

      这四个注解功能一样的,都是代表将某个类注册到容器中

    4. 作用域

      @Scope(“singleton”) @Scope(“prototype”)

    5. 小结

      xml与注解

      • xml更加万能,维护简单
      • 注解,不是自己的类,使用不了,维护复杂

      最佳实践:

      • xml用来管理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"
           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
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:annotation-config/>
        <!--指定要扫描的包-->
        <context:component-scan base-package="com.pojo"/>
    
    </beans>
    
  9. 使用Java方式配置spring

    1. 测试
      • 首先编写一个实体类,User

        @Component
        public class User {            
            //注解Value赋值
            @Value("Sha")
            private String name;
        
      • 新建一个config配置包,编写一个MyConfig配置类

        @Configuration   //代表这是一个配置类
        @ComponentScan("pojo")
        public class MyConfig {
            @Bean //通过方法注册一个bean,这里的返回值就是Bean类型,方法名就是bean的id
            public User getUser(){
                return new User();
            }
            //上面就相当于:
        //    <beans>
        //    <bean id="getUser" class="pojo.User"/>
        //    </beans>
        
        }
        
      • 测试

        public void test1(){
                //注意这里得使用注解
                ApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
                User user = ctx.getBean("getUser",User.class);
                System.out.println(user);
            }
        
      • 导入其他配制

        如果我们在编写一个配置类:

        @Configuration
        public class MyConfig2{}
        
        

        现在要在之前的配置类中导入新的配置类,用Import

        @Configuration   //代表这是一个配置类
        @ComponentScan("pojo")
        @Import(MyConfig2.class)
        public class MyConfig {
            @Bean //通过方法注册一个bean,这里的返回值就是Bean类型,方法名就是bean的id
            public User getUser(){
                return new User();
            }
            //上面就相当于:
        //    <beans>
        //    <bean id="getUser" class="pojo.User"/>
        //    </beans>
        
        }
        
  10. 代理模式

    1. 代理可分为静态代理和动态代理

    2. 代理模式:
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3RkMNSm-1598271535935)(image/代理模式.png)]

    3. 小实例(以租房为例)

      • 抽象角色:类似于 真实角色与代理角色之间 共同的行为
        //抽象角色:租房
        public interface Rent {
            public void rent();
        }
        
      • 真实角色:
        //真实角色:房东,房东要租房子
        public class Host implements Rent {
            public void rent() {
                System.out.println("房屋出租");
            }
        }
        
      • 代理角色
        //代理角色:中介
        public class Proxy implements Rent {
        
            private Host host;
        
            public Proxy(Host host) {
                this.host = host;
            }
        
            //租房
            //中介可以干房东干不了的事
            public void rent() {
                seeHouse();
                host.rent();
                fare();
            }
            //看房
            public void seeHouse(){
                System.out.println("带房客看房");
            }
            //收中介费
            public void fare(){
                System.out.println("收中介费");
            }
        }
        
      • 客户
        //客户
        public class Client {
            public static void main(String[] args){
                //真实对象必须要实例化
                Host host = new Host();
                //中介帮助房东
                Proxy proxy = new Proxy(host);
                //你去找中介租房
                proxy.rent();
            }
        }
        
    4. AOP的核心就是思想就是:在不改变原有代码的情况下,实现了对原有功能的增强

    5. 动态代理

      • 动态代理的角色跟静态是一样的
      • 动态代理的代理类是动态生成的,静态代理的代理类是提前写好的
      • 动态代理分成两类:一类是基于接口动态代理,一类是基于类的动态代理
        • 基于接口的动态代理----JDK动态代理
        • 基于类的动态代理----cglib
        • 现在用的较多的是 javasist来生成动态代理。
    6. 下面给出jdk的动态代理

      • 这里需要两个类: Proxy InvocationHandler
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DhnQb78-1598271535937)(image/invocation.png)]

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCAJ9UVr-1598271535939)(image/invoke.png)]

      • 例程

      //这个类 会自动生成代理类
      public class ProxyInvocation implements InvocationHandler {
          //被代理的接口
          private Rent rent;
      
          public void setRent(Rent rent) {
              this.rent = rent;
          }
      
          //生成代理类,重点是第二个参数,获取要代理的抽象角色!
          public Object getProxy(){
              System.out.println("输出代理类的参数");
              System.out.println(this.getClass().getClassLoader());
              System.out.println(rent.getClass().getInterfaces());
              return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
          }
          //处理代理实例上的方法调用,并返回结果
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              //添加别的参数
              seeHouse();
              //核心是通过反射实现的
              Object result = method.invoke(rent,args);
              fare();
              return result;
          }
      
          public void seeHouse(){
              System.out.println("看房子");
          }
          public void fare(){
              System.out.println("收取中介费");
          }
      }
      
      • Rent.java
      //抽象角色:租房
      public interface Rent {
          public void rent();
      }   
      
      • Host.java
      //真实角色:房东,房东要租房子
      public class Host implements Rent {
          public void rent() {
              System.out.println("房屋出租");
          }
      }
      
      • Client
      //动态代理
          public void test1(){
              //真实角色
              Rent host1 = new Host();
      
              //代理角色
              ProxyInvocation proxyInvocation = new ProxyInvocation();
      
              //通过调用程序处理角色来处理我们调用的接口对象
              proxyInvocation.setRent(host1);
      
              Rent proxy = (Rent) proxyInvocation.getProxy();
      
              proxy.rent();
          }
      
    7. 一个动态代理可以代理多个类,因为代理的是接口

  11. AOP

    1. 导入依赖:

      <dependencies>
          <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>1.9.4</version>
          </dependency>
      </dependencies>
      
    2. 第一种方式:通过Spring API实现

      • 首先编写业务接口和实现类
        public interface UserService {
            public void add();
            public void delete();
            public void query();
            public void update();
        }
        
        public class UserServiceImpl implements UserService{
        
            public void add() {
                System.out.println("add");
            }
        
            public void delete() {
                System.out.println("delete");
            }
        
            public void query() {
                System.out.println("query");
            }
        
            public void update() {
                System.out.println("update");
            }
        }
        
        
      • 写增强类,一个前置增强 一个后置增强
        //增强类 前置增强
        public class Log implements MethodBeforeAdvice {
            //method:要执行的目标对象的方法
            //objects:被调用的方法的参数
            //o:目标对象
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println(o.getClass().getName()+"的"+method.getName()+"方法被执行了");
            }
        }
        
        //增强类 前置增强
        public class Log implements MethodBeforeAdvice {
            //method:要执行的目标对象的方法
            //objects:被调用的方法的参数
            //o:目标对象
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println(o.getClass().getName()+"的"+method.getName()+"方法被执行了");
            }
        }
        
      • 去spring的文件中注册,并实现aop切入实现,注意导入约束 spring-dao.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"
               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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                                    ">
             <!--注册bean-->
             <bean id="userservice" class="demo1.pojo.UserServiceImpl"/>
             <bean id="log" class="demo1.pojo.Log"/>
             <bean id="afterlog" class="demo1.pojo.AfterLog"/>
        
            <!--配置aop-->
            <aop:config>
                <!--切入点:expression:表达式,execution(要执行的位置)-->
                <aop:pointcut id="point" expression="execution(* demo1.pojo.UserServiceImpl.*(..))"/>
                <!--执行环绕-->
                <aop:advisor advice-ref="log" pointcut-ref="point"/>
                <aop:advisor advice-ref="afterlog" pointcut-ref="point"/>
            </aop:config>
        
      • test
        @Test
            public void test1(){
                ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
                UserService userService = context.getBean("userservice", UserService.class);
                userService.add();
            }
        //结果
        
        
        
    3. 第二种方式 自定义类实现AOP,目标业务类不变,依旧还是userServiceImpl

      • 写我们自己的一个切入类
        //第二种方法:自定义类实现Aop
        public class DiyPointCut {
            public void before(){
                System.out.println("---------方法执行前--------");
            }
        
            public void after(){
                System.out.println("--------方法执行后--------");
            }
        }
        
      • 去Spring中配制
        <!--第二种方式自定义实现-->
            <!--注册bean-->
            <bean id="diy" class="demo2.DiyPointCut"/>
        
            <!--aop的配置-->
            <aop:config>
                <!--使用第二种方式:使用AOP的标签实现-->
                <aop:aspect ref="diy">
                    <aop:pointcut id="diyPointCut" expression="execution(* demo1.pojo.UserServiceImpl.*(..))"/>
                    <aop:before method="before" pointcut-ref="diyPointCut"></aop:before>
                    <aop:after method="after" pointcut-ref="diyPointCut"/>
                </aop:aspect>
            </aop:config>
        
      • 测试:
        public void test2(){
                ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
                UserService userService = context.getBean("userservice",UserService.class);
                userService.add();
            }
        
    4. 第三种方式,使用注解实现

      • 编写一个注解实现的增强类
        //使用注解的方法实现增强类
        @Aspect
        public class AnnotationPointCut {
        
            @Before("execution(* demo1.pojo.UserServiceImpl.*(..))")
            public void before(){
                System.out.println("--------方法执行前------");
            }
        
            @After("execution(* demo1.pojo.UserServiceImpl.*(..))")
            public void after(){
                System.out.println("--------方法执行后-------");
            }
        
            @Around("execution(* demo1.pojo.UserServiceImpl.*(..))")
            public void around(ProceedingJoinPoint jp) throws Throwable{
                System.out.println("环绕前");
                System.out.println("签名:"+jp.getSignature());
                //执行目标方法proceed
                Object proceed = jp.proceed();
                System.out.println("环绕后:");
                System.out.println(proceed);
            }
        
        }
        
        
      • 在spring配制文件中,注册bean,并增加支持注解的配置
        <!--第三种方式:注解实现-->
            <bean id="userservice" class="demo1.pojo.UserServiceImpl"/>
        <bean id="annotationPointCut" class="demo3.AnnotationPointCut"/>
        <aop:aspectj-autoproxy/>
        
      • test
         public void test3(){
                ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao-3.xml");
                UserService userService = context.getBean("userservice",UserService.class);
                userService.add();
            }
         //结果
            环绕前
            签名:void demo1.pojo.UserService.add()
            --------方法执行前------
            add
            环绕后:
            null
            --------方法执行后-------
        
  12. 整合mybatis
    [文档]:https://mybatis.org/spring/zh/

    1. 回忆Mybatis

      • 编写pojo的实体类
      • 实现mybatis的配置文件,包括连接数据库,别名,mappers
      • UserMapper接口编写
      • 编写对应的mapper映射文件
      • 测试
    2. MyBatis-Spring学习

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FSYAMjxv-1598271535944)(image/mybatis_1.jpg)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SnGk24Ea-1598271535945)(image/mybatis_2.jpg)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dVCWWETR-1598271535946)(image/mybatis_3.jpg)]

    3. 整合实现一:

      • (1)pojo实体类

        //建立实体类
        @Data
        public class User {
            private int id;
            private String name;
            private String pwd;
        }
        
      • (2) UserMapper.java 接口编写

        //建立mapper的接口
        public interface UserMapper {
            public List<User> selectUser();
        }
        
      • (3) UserMapper.xml 映射文件

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        
        <mapper namespace="mapper.UserMapper">
        
            <select id="selectUser" resultType="User">
                select * from user;
            </select>
        
        </mapper>
        
      • (4) 引入Spring配置文件spring-dao.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <!--第一步 导入Spring配置文件,包括 beans aop -->
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                                ">
        
      • (5) 配置数据源替换mybatis的数据源 spring-dao.xml

        <!--DataSource:使用Spring的数据源替换mybatis的配置 c3p0 dbcp
            这里使用 Spring提供的JDBC:org.springframework.jdbc.datasource-->
            <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </bean>    
        
        
      • (6)编写mybatis-config.xml

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE configuration
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-config.dtd">
        <configuration>
        
            
            <typeAliases>
                <package name="pojo"/>
            </typeAliases>
        
        
            
        </configuration>
        
      • (7) 配置SqlSessionFactory,关联MyBatis spring-dao.xml

        <!--配置sqlSessionFactory,关联mybatis-->
            <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
                <property name="dataSource" ref="datasource" />
                <!--bound mybatis-->
                <property name="configLocation" value="classpath:mybatis-config.xml"/>
                <property name="mapperLocations" value="classpath:mapper/*.xml"/>
            </bean>
        
      • (8)注册sqlSessionTemplate,关联sqlSessionFactory spring-dao.xml

        <!--注册sqlSessionTemplate,关联sqlSessionFactory-->
            <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
                <!--利用构造器注入-->
                <constructor-arg index="0" ref="sqlSessionFactory"/>
            </bean>
        
      • (9) 增加mapper接口的实现类:私有化 sqlSessionTemplate

        public class UserMapperImpl implements UserMapper{
            private SqlSessionTemplate sqlSessionTemplate;
        
            public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
                this.sqlSessionTemplate = sqlSessionTemplate;
            }
        
            public List<User> selectUser() {
                UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
                return mapper.selectUser();
            }
        }
        
        • 注意:这里的 mapper.selectUser();对应UserMapper.xml中的id
      • (10) 注册bean实现

        <!--注册bean实现-->
            <bean id="userMapper" class="mapper.UserMapperImpl">
                <property name="sqlSessionTemplate" ref="sqlSession"></property>
            </bean>
        
        • 注意 这里的id=“userMapper”,对应测试类里面的 ”userMapper“
      • (11)测试类

        public void test1(){
                ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
                UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        
                for (User user : userMapper.selectUser()) {
                    System.out.println(user);
                }
        
            }
        
    4. 整合实现2:

      • dao继承Support类,直接利用getSqlSession()获得,然后直接注入S去了S扼杀死哦你Factory,此方法不需要
        要管理SqlSessionTemplate

      • 修改(9)

        public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
            public List<User> selectUser() {
                UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
                return mapper.selectUser();
            }
        }
        
      • 修改bean的配置,去掉(8),修改(10)

        <!--第二种 修改bean Support方式-->
            <bean id="userMapper" class="mapper.UserMapperImpl2">
                <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
            </bean>
        
  13. 声明式事物
    1.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dOyxZA7c-1598271535948)(image/affair.jpg)]

    1. 事物的重要性
      • 首先 在12的案例中,给UserMapper接口新增两个方法,删除和增加用户 UserMapper.java
      
      public int addUser(User user);
      
      public int deleteUser(int id);
      
      • 然后,在UserMapper.xml中,故意把delete写错
      <mapper namespace="mapper.UserMapper">
      
          <select id="selectUser" resultType="User">
              select * from user;
          </select>
      
          <select id="addUser" parameterType="pojo.User">
              insert into user (id,name,pwd) values(#{id},#{name},#{pwd})
          </select>
      
          <select id="deleteUser" parameterType="int">
              deletes from user where id = #{id}
          </select>
      </mapper>
      
      • 编写接口的实现类

        public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
            public List<User> selectUser() {
                User user = new User(11,"明明", "123124");
        
                UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
                mapper.addUser(user);
                mapper.deleteUser(11);
                return mapper.selectUser();
            }
        
            public int addUser(User user) {
                return getSqlSession().getMapper(UserMapper.class).addUser(user);
            }
        
            public int deleteUser(int id) {
                return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
            }
        }
        
      • 测试

        public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
            public List<User> selectUser() {
                User user = new User(11,"明明", "123124");
        
                UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
                mapper.addUser(user);
                mapper.deleteUser(11);
                return mapper.selectUser();
            }
        
            public int addUser(User user) {
                return getSqlSession().getMapper(UserMapper.class).addUser(user);
            }
        
            public int deleteUser(int id) {
                return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
            }
        }
        
      • 结果报异常,但是数据插入进去的

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wFLpNleO-1598271535950)(image/affair_error.png)]

    2. Spring 声明式事务管理: 将事物管理作为横切关注点,通过aop方法模块化。Spring中通过Spring aop框架支持声明式事务管理
      • 加入头文件约束
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               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/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">
        
        
        
      • JDBC业务
         <!--声明式事务-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <constructor-arg ref="datasource" />
            </bean>
        
      • 配置事物的通知
        <!--结合aop实现事务置入-->
            <!--配置事务的类-->
            <tx:advice id="tx1" transaction-manager="transactionManager">
                <!--给哪些方法配置事务-->
                <!--配置事务的传播特性-->
                <tx:attributes>
                    <tx:method name="add*" propagation="REQUIRED"/>
                    <tx:method name="delete*" propagation="REQUIRED"/>
                    <tx:method name="update" propagation="REQUIRED"/>
                    <tx:method name="*" propagation="REQUIRED"/>
                    <tx:method name="query" read-only="true"/>
                </tx:attributes>
            </tx:advice>
        
        • 事物的传播

          [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjlRKWxq-1598271535953)(image/chuanbo.jpg)]

      • 配置AOP 织入事务
         <!--配置事务切入-->
            <aop:config>
                <aop:pointcut id="txpointxut" expression="execution(* mapper.*.*(..))"/>
                <aop:advisor advice-ref="tx1" pointcut-ref="txpointxut"/>
            </aop:config>
        
      • 整个transacation-spring.xml
        <?xml version="1.0" encoding="UTF-8"?>
        <!--第一步 导入Spring配置文件,包括 beans aop -->
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               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/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">
        
            <!--DataSource:使用Spring的数据源替换mybatis的配置 c3p0 dbcp
            这里使用 Spring提供的JDBC:org.springframework.jdbc.datasource-->
            <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </bean>
        
            <!--配置sqlSessionFactory,关联mybatis-->
            <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
                <property name="dataSource" ref="datasource" />
                <!--bound mybatis-->
                <property name="configLocation" value="classpath:mybatis-config.xml"/>
                <property name="mapperLocations" value="classpath:mapper/UserMapper.xml"/>
            </bean>
        
            <!--声明式事务-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <constructor-arg ref="datasource" />
            </bean>
        
            <!--结合aop实现事务置入-->
            <!--配置事务的类-->
            <tx:advice id="tx1" transaction-manager="transactionManager">
                <!--给哪些方法配置事务-->
                <!--配置事务的传播特性-->
                <tx:attributes>
                    <tx:method name="add*" propagation="REQUIRED"/>
                    <tx:method name="delete*" propagation="REQUIRED"/>
                    <tx:method name="update" propagation="REQUIRED"/>
                    <tx:method name="*" propagation="REQUIRED"/>
                    <tx:method name="query" read-only="true"/>
                </tx:attributes>
            </tx:advice>
        
            <!--配置事务切入-->
            <aop:config>
                <aop:pointcut id="txpointxut" expression="execution(* mapper.*.*(..))"/>
                <aop:advisor advice-ref="tx1" pointcut-ref="txpointxut"/>
            </aop:config>
        
        
        </beans>
        
      • applicationContext.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">
        
            <import resource="transaction-spring.xml"/>
        
            <!--第二种 修改bean Support方式-->
            <bean id="userMapper" class="mapper.UserMapperImpl2">
                <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
            </bean>
        
        </beans>
        
      • test
        public void test1(){
                ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
                UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        
                for (User user : userMapper.selectUser()) {
                    System.out.println(user);
                }
            }
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值