spring学习

1、Spring

1.1、简介

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

外部依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.5</version>
</dependency>

1.2、优点

  • Spring 是一个开源的免费框架(容器)!
  • Spring是一个轻量级的非入侵式的框架!
  • 控制反转(IOC)面向切面编程(AOP)!
  • 支持事务的处理,对框架的整合支持!

总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!

1.3组成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ubeMHVdZ-1618316950301)(Spring.assets/20180914091500764)]

1.4拓展

现代化的java开发,就是基于Spring的开发

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

  • Spring Boot
    • 一个快速开发的脚手架
    • 基于Spring Boot可以快速开发单个微服务。
    • 约定大于配置
  • Spring Cloud
    • 基于Spring Boot 的实现。

学习Spring Boot的前提,需要完全掌握Spring和Spring MVC!

弊端:发展了太久,违背了原来的理念!配置十分繁琐

2、IOC理论推导

  1. UserDao接口
  2. UserDaoImpl实现类
  3. UserService业务接口
  4. UserServiceImpl业务代码实现类

我们在之前的业务中,用户的需求可能会影响我们原来的代码,我们需要更具用户的需求,去修改原来的代码!如果原来代码十分庞大,修改的成本十分昂贵。

我们使用set接口实现

 private  UserDao userDao;
//利用set方法实现动态实现值的输入
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
  • 之前,程序猿主动创建对象!控制权在程序猿手上!
  • 使用set注入之后,程序不在具有主动性,而实变成了被动的接收对象!

这种思想,从本质上解决了问题,程序猿不用在去管理对象的创建了。系统的耦合性大大降低,可以更加专注在业务的实现上,这位是IOC的原型!

IOC本质

控制反转IOC,是一种思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI知识IOC的另一种说话。没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序种,对象的创建由程序自己控制,控制反转后将都西昂的创建转移给第三方,个人认为所谓控制反转,就是:获得依赖对象的方式反转了。

采用XML方式配置Bean的时候,Bean的定义信息式和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类种,从而达到了零配置额目的。

控制反转是一种通过描述(XML或注解)并通过第三方去产生或获取特定对象的方式。在Spring中实现控制反转的时IOC容器,其实现方法是依赖注入

3、HelloSpring

  • Hello 对象谁创建的?

    hello 对象是由Spring创建的

  • Hello 对象的属性是怎么设置的?

    hello 对象是由Spring 容器设置的

这个过程就叫做控制反转:

控制:谁来控制对象的创建,传统的程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring 创建的

反转:程序本身不创建对象,而变成被动的接收对象

依赖注入:就是利用set方法来进行注入的。

IOC是一种编程思想,由主动的编程编程被动的接收。

所以到现在,我们彻底不用在原来的程序中修改代码了,要实现不同的操作,只需要在xml配置中进行修改,所谓的IOC, 用一句话搞定:对象由Spring来创建,管理,装配!

4、IOC创建对象的方式

  1. 使用无参构造创建对象

    //        当new一个对象的时候自动的就走了他的无参构造方法
    //        User user = new User();
            //获取Spring的上下文对象
    //        这里同样自动走了无参构造方法相当于Spring自动帮我们new一个对象
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            User user = (User) context.getBean("user");
            user.show();
    
  2. 假设我们需要有参构造创建对象。

    1. 下标赋值

      <bean id="user" class="com.lv.pojo.User">
      <!--下标赋值-->
          <constructor-arg index="0" value=""/>
      </bean>
      
    2. 类型

          <bean id="user" class="com.lv.pojo.User">
      <!--       第二种方式: type:基本类型可以直接使用
                      引用类型必须使用全限定名
      
                      不建议使用
      
      ,当参数有多个相同类型的时候就无法准确的定位参数-->
           <constructor-arg type="java.lang.String" value="无敌"/>
          </bean>
      
    3. 参数名
    
       ```xml
       <bean id="user" class="com.lv.pojo.User">
           <!--       第三种方式:直接通过参数名设置-->
           <constructor-arg name="name" value="spring"/>
       </bean>
    

在配置文件加载的时候,其中管理的对象已经初始化了!

5、Spring配置

5.1、别名

<bean id="user" class="com.lv.pojo.User">
        <!--       第三种方式:直接通过参数名设置-->
        <constructor-arg name="name" value="spring"/>
    </bean>
<!--   别名,如果添加了别名,我们也可以使用别名获取这个对象-->
    <alias name="user" alias="admin"/>

5.2、Bean的配置

<!--    id:bean的唯一标识符
        class:bean对象所对应的全限定名:包名+类名
        name:也是别名,而且name更高级,可以同时取多个别名,使用的时候用逗号,或者空格,或者分号隔开-->
<bean id="userT" class="com.lv.pojo.UserT" name="t,pojo">
    <constructor-arg name="name" value="supper"/>
</bean>

5.3、import

import,一般用于团队开发,它可以将多个配置文件,导入合并为一个

假设项目中有多个开发,这个三个人负责不同的类开发,和不同的类需要组测在不同的Bean中,我们可以利用Import将所有人的beans.xml合并到一个新的xml中,最后我们只需要使用新的ApplicationContext.xml就可以使用全部的类

  • A
  • B
  • C
  • ApplicationContext.xml
<import resource="beans.xml1"/>
<import resource="beans.xml2"/>
<import resource="beans.xml3"/>

6、依赖注入

6.1、构造器注入

6.2、Set方式注入

  • 依赖注入:set注入
    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象的所有属性是由容器注入!

【环境搭建】

  1. 复杂类型

    package com.lv.pojo;
    
    public class Address {
        private  String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
  2. 真实测试对象

    public class Student {
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobby;
        private Map<String,String> card;
        private Set<String> games;
        private  String wife;
        private Properties info;
    }
    
    1. 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="student" class="com.lv.pojo.Student">
      <!--        普通值的注入-->
              <property name="name" value="张山"/>
          </bean>
      </beans>
      
    2. 测试类

      public class MyTest {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
              Student student = (Student) context.getBean("student");
              System.out.println(student.getName());
          }
      }
      
    3. 全部

      <?xml version="1.0" encoding="UTF-8"?>

      <bean id="student" class="com.lv.pojo.Student">
          <!-- 第一种:普通值的注入 value-->
          <property name="name" value="张山"/>
          <!-- 第二种,Bean注入 ref-->
          <property name="address" ref="address"></property>
          <!-- 数组注入-->
          <property name="books">
              <array >
                  <value>红楼梦</value>
                  <value>西游记</value>
                  <value>水浒传</value>
                  <value>三国演义</value>
              </array>
          </property>
          <!-- list注入-->
          <property name="hobby">
              <list>
                  <value>听歌</value>
                  <value>敲代码</value>
                  <value>看电影</value>
              </list>
          </property>
          <!-- Map注入-->
          <property name="card">
              <map>
                  <entry key="身份证" value="566+999566669845698"/>
                  <entry key="银行卡" value="566+852524524555552"/>
              </map>
          </property>
          <!-- Set注入-->
          <property name="games">
              <set>
                  <value>LOL</value>
                  <value>农药</value>
              </set>
          </property>
          <!-- 空值注入-->
          <property name="wife">
              <null/>
          </property>
          <!-- Properties注入-->
          <property name="info">
              <props>
                  <prop key="driver">451542154</prop>
                  <prop key="url"></prop>
                  <prop key="username">李四</prop>
                  <prop key="password">李四</prop>
              </props>
          </property>
      </bean>
      
      <bean id="address" class="com.lv.pojo.Address">
          <property name="address" value="北京"/>
      </bean>
      </beans>
      

6.3、拓展方式注入

我们可以使用p命名空间和c命名空间注入

官方解释:1.4.2 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 命名空间注入 可以直接注入属性的值-->
    <bean id="user" class="com.lv.pojo.User" p:name="王五" p:age="18"/>
<!--c 命名空间可以通过构造器注入-->
    <bean id="user2" class="com.lv.pojo.User" c:name="赵四" c:age="19"/>
</beans>

测试:

@Test
public void  test(){
    ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
    User user = (User) context.getBean("user");
    User user2 = (User) context.getBean("user2");
    System.out.println(user);
    System.out.println(user2);
}

注意点:P命名和C命名空间不能直接使用,需要导入约束xml

 xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"//需要有参构造

6.4、bean的作用域

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

  1. 单例模式(Spring默认机制)

    为同一个对象

    <bean id="user" class="com.lv.pojo.User" p:name="王五" p:age="18" scope="singleton"/>
    
  2. 原型模式

    每次从容器中get的时候,都会产生一个新的对象!

    <bean id="user" class="com.lv.pojo.User" p:name="王五" p:age="18" scope="prototype"/>
    

其余的request,session,application、这些只能在web开发中使用

7、Bean的自动装配

  • 自动装配式Spring满足bean依赖的一种方式!
  • Spring会在上下文是中自动寻找,并自动给bean装配属性!

在Spring中有三种装配方式

  1. 在xml中显示的配置
  2. 在java显示配置
  3. 隐式的自动装配

7.1、测试

环境搭建:一个人有两个宠物

7.2、ByName自动装配

<!--    byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的bean id
-->
    <bean id="people" class="com.lv.pojo.People" autowire="byName">
        <property name="name" value="张三"/>
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
    </bean>

7.3、ByType自动装配

    <bean id="cat" class="com.lv.pojo.Cat"/>
    <bean id="dog11" class="com.lv.pojo.Dog"/>
<!--    byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的bean id    只要id相同就就可以装配否则就失败
        bytype:会自动在容器上下文中查找和自己对象属性类型相同的bean   必须保证同类型的的bean全局唯一,有多个同类型的bean就会失败
-->
    <bean id="people" class="com.lv.pojo.People" autowire="byType">
        <property name="name" value="张三"/>
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
    </bean>

小结:

  • **byname:**的时候需要保证,所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
  • **bytype:**的时候需要保证,所有的bean的类型唯一,并且这个bean需要和自动注入的属性类型一致

7.4、使用注解实现自动装配

jdk1.5支持,Spring2.5支持

要使用注解须知:

  1. 导入约束 context约束

  2. 配置注解的支持 context:annotation-config/

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

@Autowired

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

使用Autowired可以不用编写set方法,前提是自动装配的属性在ioC(Spring)容器中存在,且符合bytype条件!

科普:

//@Nullable  字段标记了这个注解,说明这个字段可以为null 

//参数为空的时候也不会报错
 public People(@Nullable Cat cat, Dog dog, String name) {
        this.cat = cat;
        this.dog = dog;
        this.name = name;
    }
//如果显示定义了Autowired属性为false,说明这个对象的属性可以为null,否则的话不允许为空
@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;
private String name;

如果@Autowired自动装配比较复杂,自动装配无法通过一个注解完成就需要@Qualifier(value"xxx”)去配合@Autowired使用,指定唯一的bean注入

当bean有多个同类型属性就需要利用@Qualifier(value = “dog23”)

@Autowired
@Qualifier(value = "dog23")
private Dog dog;
<bean id="dog2dsaf" class="com.lv.pojo.Dog"/>
<bean id="dog23" class="com.lv.pojo.Dog"/>

还有一个@Resource注解

区别

@Resource和@Autowired

  • 都是来自动装配的,都可以放在属性字段上
  • @Autowired 通过bytype方式实现,而且必须要求这个对象存在!【常用】
  • @Resource默认通过byname的方式实现,如果找不到名字则通过bytype实现,如果都找不到就报错【常用】
  • 执行顺序不同

8、使用注解开发

在Spring 4之后,要使用注解开发,必须要保证 aop 的包导入了

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

使用注解需要导入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>
  1. bean

  2. 属性如何注入

    package com.lv.pojo;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    //等价于<bean id="user" class="com.lv.pojo.User"/>
    //@Component 组件
    @Component
    public class User {
        //相当于<property name="name" value="法外狂徒"/>
        @Value("法外狂徒")
        public String name;
    }
    
  3. 衍生的注解

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

    • dao【@Repository】
    • service【@Service】 这四个注解功能都是一样的,都是代表将某个类注册到Spring中装配Bean
    • controller【@Controller】
  4. 自动装配

  5. 作用域

  6. 小结

    xml 与注解:

    • xml更加万能,使用任何场合!维护更加简单
    • 注解不是自己的类使用不了,维护相对复杂

最佳实践:

  • xml用来管理bean
  • 注解只负责属性的注入
  • 我们在使用过程中,只需要注意一个问题,必须要开启注解支持

9、使用java的方式配置Spring

我们现在要完全不使用Spring xml配置了,全权交给java来做!

javaConfig 是Spring的一个子项目,在Spring 4之后,它成为了核心功能

环境

@Configuration//这个也会有Spring容器托管,注册到容器中,因为它本来就是一个@Component,
@ComponentScan("com.lv.pojo")
public class MyConfig {
    //注册一个bean,就相当于我们之间写的一个bean标签,这个方法的名字就相当于id 返回值相当于class
    @Bean
    public User getUser(){
        return new User();//就是返回要注入的bean的对象
    }
@Component
public class User {
    @Value("小明")
    private String name;

    public String getName() {
        return name;
    }


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

    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

测试类

public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了注解的方式去做,我们只能通过AnnotationConfigApplicationContext(写的配置类.class)来获取容器
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("getUser", User.class);//取方法名
        System.out.println(user.getName());
    }
}

这种纯java配置中,在SpringBoot中随处可见!

10、代理模式

10.1、静态代理模式

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们会做一些附属操作
  • 客户:访问代理的人

代码步骤:

  1. 接口

    package com.lv.demo;
    //租房
    public interface Rent {
        public void rent();
    }
    
  2. 真实角色

    package com.lv.demo;
    //房东
    public class Host implements Rent{
    
        public void rent() {
            System.out.println("房东出租房子");
        }
    }
    
  3. 代理角色

    package com.lv.demo;
    
    public class Proxy implements Rent {
        private Host host;
    
        public void setProxy(Host host) {
            this.host = host;
        }
    //代理角色出租房子
        public void rent() {
            host.rent();
            seeHose();
            fare();
        }
    //代理看房
        public void seeHose(){
            System.out.println("中介带你看房");
        }
    // 代理收中介非
        public void fare(){
            System.out.println("中介收取中介费");
        }
    }
    
  4. 客户端访问代理角色

    package com.lv.demo;
    
    public class Client {
        public static void main(String[] args) {
            Host host=new Host();
            Proxy proxy = new Proxy();
            proxy.setProxy(host);
            proxy.rent();
        }
    }
    

代理模式的好处:

  • 可以使真实角色操作更加存粹,不用取关注公共的业务
  • 公共业务就交给了代理角色!实现了业务的分工
  • 公共业务发生了拓展的时候方便集中管理

缺点:

  • 一个真实角色就有一个代理角色,代码量翻倍,开发效率变低

10.2、代理加深

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

当产品已经完成上线的时候,我们需要新增一些功能,就需要横向开发

例如:我们操作数据增删改查,当一段时间后我想在完成这个操作的时候打印log这时候,我们不能去修改原有的代码,需要用到横向的开发 代理中添加,而不是去真实角色的修改原有的代码

接口:

package com.lv.demo02;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

真实角色:真实角色只做数据操作,需要添加其他的操作就交给代理层

package com.lv.demo02;

public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个数据");
    }

    public void delete() {
        System.out.println("删除了一个数据");
    }

    public void update() {
        System.out.println("修改了一个数据");
    }

    public void query() {
        System.out.println("查询了一个数据");
    }
}

代理角色:代理不仅完成的真实角色的数据操作功能,自己还可以增加额外的功能:打印日志

package com.lv.demo02;

public class UserServiceImplProxy implements UserService {
    private UserServiceImpl userServiceImpl;
//一般使用set方法
    public void setUserServiceImplProxy(UserServiceImpl userServiceImpl) {
        this.userServiceImpl = userServiceImpl;
    }
//代理角色完成了代理实现了这些功能
    public void add() {
        userServiceImpl.add();
        log("add");

    }

    public void delete() {
        userServiceImpl.delete();
        log("delete");
    }

    public void update() {
        userServiceImpl.update();
        log("update");
    }

    public void query() {
        userServiceImpl.query();
        log("query");
    }

    //增加一个打印日志的功能
    public void log(String msg){
        System.out.println("[debug] 使用"+msg+"方法");
    }
}

客户端访问代理角色:

package com.lv.demo02;

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        UserServiceImplProxy proxy= new UserServiceImplProxy();
        proxy.setUserServiceImplProxy(userServiceImpl);

        //代理角色代理完成了
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.query();
        //当我们需要增加功能时
    }
}

10.3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类的:基于接口的动态代理、基于类的动态代理
    • 基于接口----JDK动态代理
    • 基于类:cglib
    • java字节码实现:javasist

需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序

动态代理的好处:

  • 可以使真实角色操作更加存粹,不用取关注公共的业务
  • 公共业务就交给了代理角色!实现了业务的分工
  • 公共业务发生了拓展的时候方便集中管理
  • 一个动态代理类是代理的一个接口一般,就是对应的一类业务
  • 一个动态代理类,可以代理多个类,只要实现了同一个接口

这个动态代理可以提取一个方法,改变其需要被代理的接口target就可以了

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

//等会我们会用这个类自动生成代理,生成动态代理对象的类
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;//只需要改变target就可以改变需要代理的对象,target是接口
    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
      return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //处理代理实例并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
}

11、AOP

11.1、什么是AOP

AOP:意味:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发的一个热点,也是Spring框架的一个重要内容,是函数式编程的一种衍生范型。利用Aop可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分耦合性降低,提高程序的可重用性,同时提高了开发是效率。

11.2、Aop在Spring中的作用

提供事务声明;允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即:于我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,缓存,事务等等……
  • 切面(ASPECT):横切关注点被模块化的特殊对象,即,他是一个类
  • 通知(Advice):切面必须完成的工作,即,他是一个方法
  • 目标(Target):被通知的对象
  • 代理(Proxy):向目标对象 应用 通知后创建的对象
  • 切入点(PointCut):切面通知执行的”地点“的定义。
  • 链接点(JiontPoint):与切入点匹配的执行点。

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

11.3、使用Spring实现AOP

【重点】 使用AOP,需要导入一个依赖包!

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

方式一:使用Spring的API接口【主要是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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         https://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop
         https://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="userService" class="com.lv.service.UserServiceImpl"/>
    <bean id="log" class="com.lv.log.Log"/>
    <bean id="afterLog" class="com.lv.log.AfterLog"/>
<!--方式一:使用原生Spring API接口-->
<!--    配置AOP:需要导入aop约束-->
    <aop:config>
        <!--        切入点:expression:表达式 execution(要执行的位置 修饰词 返回值 类名 方法名 参数)-->
        <aop:pointcut id="pointCut" expression="execution(* com.lv.service.UserServiceImpl.*(..))"/>
<!--        执行环绕增强-->
        <aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
    </aop:config>
</beans>

方式二:使用自定义类来实现【主要是切面实现】

<!--    方式二:使用自定义类-->
    <bean id="diy" class="com.lv.diy.DiyPointCut"/>
    <aop:config>
<!--        自定义切面,ref要引用的类-->
        <aop:aspect ref="diy">
<!--        切入点-->
            <aop:pointcut id="pointCut" expression="execution(* com.lv.service.UserServiceImpl.*(..))"/>
<!--        通知-->
            <aop:before method="before" pointcut-ref="pointCut"/>
            <aop:after method="after" pointcut-ref="pointCut"/>
        </aop:aspect>
    </aop:config>

方式三:使用注解实现!

package com.lv.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;



//使用注解方式实现AOP
@Aspect//标注这个类是一个切面
public class AnnotationPointCut {
    @Before("execution(* com.lv.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("===============方法执行前===============");
    }
    @After("execution(* com.lv.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("===============方法执行后===============");
    }
    //在环绕增强中,我们可以给定一个参数,代表我们需要获取处理切入的点
    @Around("execution(* com.lv.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Signature signature = jp.getSignature();//获得签名
        System.out.println("signature:"+signature);
//执行方法
        Object proceed = jp.proceed();

        System.out.println("环绕后");
        System.out.println(proceed);

    }

}

12、整合Mybatis

步骤:

  1. 导入相关jar包

    • junit

    • mybatis

    • mysql数据库的

    • spring相关的

    • aop织入

    • mybatis-spring【new 】

      <dependencies>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.13.1</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.47</version>
              </dependency>
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis</artifactId>
                  <version>3.5.2</version>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.3.5</version>
              </dependency>
      <!--        spring连接数据库还需要一个spring-jdbc-->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-jdbc</artifactId>
                  <version>5.1.9.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjweaver</artifactId>
                  <version>1.9.6</version>
              </dependency>
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis-spring</artifactId>
                  <version>2.0.2</version>
              </dependency>
          	<dependency>
                   <groupId>org.projectlombok</groupId>
                   <artifactId>lombok</artifactId>
                   <version>1.18.10</version>
              </dependency>
          </dependencies>
      
  2. 编写配置文件

  3. 测试

12.1、会议mybatis

  1. 编写实体类
  2. 编写核心配置
  3. 编写接口
  4. 编写Mapper.xml
  5. 测试

12.2、Mybatis-Spring

  1. 编写数据源
  2. sqlSessionFactory
  3. sqlSessionTemplate
  4. 需要给接口加实现类
  5. 将自己写的实现类,注入到Spring中

spring-10-mybatis

13、声明式事务

1、回顾事务

  • 把一组业务当成一个业务;要么都成功要么都失败
  • 事务在项目开发中十分的重要,涉及到数据的一致性
  • 确保完整性和一致性

事务的ACID原则;

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务操作同一个资源,相互隔离不干扰,防止数据损坏
  • 持久性
    • 事务一旦提交,无论发生什么问题,结果都不会在被影响

2、Spring中的事务管理

  • 声明式事务 :AOP
  • 编程式事务 :需要在代码中,进行事务的管理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值