Spring学习笔记

1、Spring

1.1简介

​ Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

  • Spring理念:是现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
  • SSH :Struct2+Spring+Hibernate
  • SSM:SprMVC+Spring+Mybatis

1.2优点

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

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

1.3组成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZIqWxZ4-1652524609583)(D:\Desktop\学习笔记\图片\image-20220510150011761.png)]

1.4扩展

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cjUFaAy7-1652524609584)(D:\Desktop\学习笔记\图片\image-20220510150319012.png)]

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

现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提需要完全掌握Spring和SpringMVC!

弊端:配置太繁琐,人称“配置地狱”

2、IOC理论推导

例:

​ 用户操作数据库的本质是通过调用service层来调用Dao层,所以用户只需要调用Service层的方法就可以操作数据库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrBV1ybu-1652524609586)(D:\Desktop\学习笔记\图片\image-20220510154605949.png)]

UserServiceImpl:

package com.cjp.service;

import com.cjp.dao.UserDao;
import com.cjp.dao.UserDaoImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao = new UserDaoImpl();

    @Override
    public void getUserService() {
        userDao.getUser();
    }
}

分析:此时UserServiceImpl中的userDao是固定死的,而当UserDao接口的实现类有多个,用户需要使用不同的实现时,就需要修改UserServiceImpl的源码。

优化后的UserServiceImpl:

package com.cjp.service;

import com.cjp.dao.UserDao;

public class UserServiceImpl implements UserService{
    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUserService() {
        userDao.getUser();
    }
}

分析:修改后UserServiceImpl中的UserDao是没有确定的,而是通过构造器来创建。

前后对比:

  • 之前,程序主动创建对象,控制权在程序员手上!
  • 使用set注入后,程序不再具有主动性,控制权在用户,程序被动接受对象!

这种思想,从本质上解决了问题,当用户有不同需求时,不需要去修改源码,降低了系统耦合性,可以更加专注在业务的实现上!这是IOC的原型!

IOC本质

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

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

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

3、HelloSpring

1.先建一个实体类Hello:

package com.cjp.pojo;

public class Hello {
    private String string;

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }

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

2.在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="hello" class="com.cjp.pojo.Hello">
    <property name="string" value="Spring"/>
 </bean>

</beans>

3.测试

import com.cjp.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello);
    }
}

4、IOC创建对象的方式

1、使用无参构造创建对象,默认!

2、假设我们要使用有参构造创建对象。

  • 下标赋值

     <bean id="user" class="com.cjp.pojo.User">
        <constructor-arg index="0" value="cjp"/>
     </bean>
    
  • 类型赋值

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

    <bean id="user" class="com.cjp.pojo.User">
        <constructor-arg name="name" value="cjp"/>
    </bean>
    

总结:在配置文件加载的时候,容器中注册的对象就已经初始化了

5、Spring配置

  • 别名
<alias name="user" alias="newUser"/>

设置了别名后,也可以使用别名来获取到对象。

  • Bean的配置
id:bean的唯一标识符,也就相当于对象名
class:bean对象所对应的全限定名:包名+类名
name:也是别名,而且name可以同时设置多个别名,使用逗号、空格、分号等分隔
  • import

当团队开发时,创建了多个beans配置文件,可用import来将多个配置文件导入合并成一个

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

    <import resource="beans.xml"/>
    <import resource="beans1.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>

</beans>

6、依赖注入

6.1、构造器注入

​ 使用构造器注入属性

6.2、set方式注入(重点)

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

搭建环境

1.创建复杂实体类:

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
    //getter setter toString方法省略
package com.cjp.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

2.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.cjp.pojo.Address">
       <property name="address" value="湖南省长沙市岳麓区"/>
   </bean>

   <bean id="student" class="com.cjp.pojo.Student">
       <!--普通注入-->
       <property name="name" value="cjp"/>
       <!--bean注入-->
       <property name="address" ref="address"/>
       <!--数组注入-->
       <property name="books">
           <array>
               <value>《计算机组成原理》</value>
               <value>《操作系统》</value>
               <value>《编译原理》</value>
               <value>《计算机网络》</value>
           </array>
       </property>
       <!--List注入-->
       <property name="hobbys">
           <list>
               <value></value>
               <value></value>
               <value>rap</value>
               <value>篮球</value>
           </list>
       </property>
       <!--Map注入-->
       <property name="card">
           <map>
               <entry key="饭卡" value="12143432"/>
               <entry key="校园卡" value="2435657"/>
               <entry key="银行卡" value="3943759536784"/>
           </map>
       </property>
       <!--Set注入-->
       <property name="games">
           <set>
               <value>原神</value>
               <value>王者荣耀</value>
               <value>火影忍者</value>
           </set>
       </property>
       <!--null注入-->
       <property name="wife">
           <null/>
       </property>
       <!--properties注入-->
       <property name="info">
           <props>
               <prop key="学号">20192712</prop>
               <prop key="班级">风景园林2班</prop>
               <prop key="身高">183cm</prop>
           </props>
       </property>


   </bean>

</beans>

3.测试

import com.cjp.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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);
    }
    /*Student{
              name='cjp',
              address=Address{address='湖南省长沙市岳麓区'},
               books=[《计算机组成原理》, 《操作系统》, 《编译原理》, 《计算机网络》],
                hobbys=[唱, 跳, rap, 篮球],
                card={饭卡=12143432, 校园卡=2435657, 银行卡=3943759536784},
                games=[原神, 王者荣耀, 火影忍者],
                wife='null',
                info={学号=20192712, 班级=风景园林2班, 身高=183cm}}
     */
}

6.3、拓展方式注入

  • P命名空间与C命名空间
<?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">

    <bean id="user" class="com.cjp.pojo.User" p:age="18" p:name="cjp"/>
    <bean id="user2" class="com.cjp.pojo.User" c:name="aas" c:age="10"/>

</beans>

注意:

1.p命名空间和c命名空间不能直接使用,需要导入xml约束

2.p命名需要无参构造

3.c命名需要有构造

6.4、bean的作用域

1、单例模式(Spring默认)

<bean id="user2" class="com.cjp.pojo.User" c:name="aas" c:age="10" scope="singleton"/>

2、原型模式:每次从容器中get都会产生一个新对象!

<bean id="user2" class="com.cjp.pojo.User" c:name="aas" c:age="10" scope="prototype"/>

3、request、session、application

只在web开发中使用到!

7、Bean的自动装配

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

三种装配的方式:

  • 在xml中显示配置
  • 在Java中显示配置
  • 隐式的自动装配bean【重要】

7.1、测试

1.搭建环境

一个人有两个宠物!

  • ByName
	<!--bean id要与需要自动装配的类的属性名对应-->
	<bean id="cat" class="com.cjp.pojo.Cat" ></bean>
    <bean id="dog" class="com.cjp.pojo.Dog" ></bean>
    <bean id="person" class="com.cjp.pojo.Person" autowire="byName" >
        <property name="name" value="cjp"/>
    </bean>
  • ByType
    <!--bean id可以不要要与需要自动装配的类的属性名对应 类型相对应就行了-->
	<bean id="ca" class="com.cjp.pojo.Cat" ></bean>
    <bean id="do" class="com.cjp.pojo.Dog" ></bean>
    <bean id="person" class="com.cjp.pojo.Person" autowire="byType" >
        <property name="name" value="cjp"/>
    </bean>
  • 使用注解自动装配

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"
       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.@Autowired

当容器中的bean类型与Person类属性唯一对应时,可以只是用@Autowired

@Autowired可以在实体类属性上使用,也可以在setter方法上使用;在属性上使用后可以不用写setter方法了。

Person:

public class Person {
    @Autowired
    private Dog dog;
    @Autowired
    private Cat cat;
    private String name;
    
    //getter setter 方法省略
}

beans.xml:

   	<bean id="cat" class="com.cjp.pojo.Cat" ></bean>
    <bean id="dog" class="com.cjp.pojo.Dog" ></bean>
    <bean id="person" class="com.cjp.pojo.Person" />

4.@Qualifier

当容器中同一个类有多个实例是 ,注入时就存在争议,这是仅仅使用@Autowired就不行了

还需要使用@Qualifier来制定要注入的实例名

    <bean id="cat111" class="com.cjp.pojo.Cat" ></bean>
    <bean id="cat11" class="com.cjp.pojo.Cat" ></bean>
    <bean id="dog111" class="com.cjp.pojo.Dog" ></bean>
    <bean id="dog11" class="com.cjp.pojo.Dog" ></bean>
    <bean id="person" class="com.cjp.pojo.Person" />
public class Person {
    @Autowired
    @Qualifier(value = "dog11")
    private Dog dog;
    @Autowired
    @Qualifier(value = "cat111")
    private Cat cat;
    private String name;
}

5.@Resource

public class Person {
    @Resource(name = "dog11")
    private Dog dog;
    @Resource(name = "cat111")
    private Cat cat;
    private String name;
}

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过ByType的方式实现
  • @Resource默认通过ByName的方式实现,如果找不到名字,则通过ByType实现,若果两个都找不到就报错!
  • 执行顺序不同:@Autowired通过ByType的方式实现。

8、使用注解开发

在Spring4

之后之后,要是用注解开发,必须要保证导入了AOP的包。

使用注解需要导入context约束,增加注解的支持。

1、bean

  • 导入约束

    <context:component-scan base-package="com.cjp.pojo"/>
    
  • 使用注解

    package com.cjp.pojo;
    
    import org.springframework.stereotype.Component;
    
    //相当于<bean id="user" class="com.cjp.pojo.User"/>
    @Component
    public class User {
        public String name="cjp";
    }
    
    

2、属性如何注入

@Component
public class User {
    /*   相当于<bean id="user" class="com.cjp.pojo.User">
        <property name="name" value="cjp"/>
    </bean>*/
    @Value("cjp")
    public String name;
}

3、衍生的注解

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

  • dao 【@Repository】
  • service 【@Service】
  • controller 【@Controller】

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

4、自动装配

@Autowired:自动装配通过名字、类型
     若果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
@Nullable  字段标记了这个注解,说明这个字段可以为null
@Resource:自动装配通过名字、类型

5、作用域

@Scope("prototype")
public class User {
    /*   相当于<bean id="user" class="com.cjp.pojo.User">
        <property name="name" value="cjp"/>
    </bean>*/
    @Value("cjp")
    public String name;
}

6、小结

xml与注解:

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

xml与注解的最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入;
  • 我们在使用的过程中,要注意开启注解支持

9、使用java 的方式配置Spring

使用java配置类来取代xml配置文件。

JavaConfig是Spring的一个子项目,在Spring4之后,他成为了一个核心功能!

1.实体类

package com.cjp.pojo;

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

//表明这个类被Spring接管了,注册到了容器中
@Component
public class User {
    //注入属性
    @Value("cjp")
    private String name;

    public String getName() {
        return name;
    }

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

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

2.配置类MyConfig

package com.cjp.config;

import com.cjp.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;


@Configuration//代表这是一个配置类,相当于beans.xml
//这个也会被Spring容器托管,注册到容器中,因为他本来就是一个@Component
@ComponentScan("com.cjp.pojo")
@Import(MyConfig2.class) //导入其他配置类
public class MyConfig {

    /*相当于beans.xml中的bean标签
    * 方法名就相当于标签中的id
    * 方法的返回值就相当于标签中的class*/
    @Bean
    public User getUser(){
        return new User();//返回要注入到bean的对象
    }
}

3.测试类

import com.cjp.config.MyConfig;
import com.cjp.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser.getName());
    }
}

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

10、代理模式

代理模式是SpringAOP的底层!

代理模式的分类:

  • 静态代理

​ 真实角色(Real)

​ 代理角色(proxy)

​ 客户端(Client)

  • 动态代理

    • 动态代理角色和静态代理角色一样
    • 动态代理的代理类时动态生成的,不是我们直接写好的
    • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口:JDK动态代理 【我们在这里使用的】
    • 基于类:Cglib
    • java字节码实现:JAVAsist

    1.接口

    package com.cjp.demo01;
    
    public interface Rent {
        public void rent();
    }
    
    

    2.真实角色

    package com.cjp.demo01;
    
    public class Host implements Rent{
        @Override
        public void rent() {
            System.out.println("房东出租房屋!");
        }
    }
    
    

    3.生成动态代理类的工具类

    package com.cjp.demo01;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyInvokeHandler implements InvocationHandler {
        //被代理的接口
        private Object target;
    
        public void setRent(Object target) {
            this.target = target;
        }
    
        //生成得到代理类
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
        //处理代理实例,并返回结果
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            Object result = method.invoke(target, args);
            return result;
        }
    }
    
    

    4.测试类

    package com.cjp.demo01;
    
    import java.lang.reflect.Proxy;
    
    public class Client {
        public static void main(String[] args) {
            Host host = new Host();//真实角色
            ProxyInvokeHandler pih = new ProxyInvokeHandler();
            pih.setRent(host);
            Rent proxy = (Rent) pih.getProxy();
            proxy.rent();
        }
    }
    
    

    动态代理类代理的是一个接口,所以可以代理多个实现类,只需要修改注入的实现类即可

11.AOP实现

导入依赖

		<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

方式一:使用Spring的API接口[主要是SpringAPI接口实现]

1.接口

2.接口实现类

3.日志类

package com.cjp.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class After implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("使用了"+method.getName()+"方法,返回值为:"+o);
    }
}

package com.cjp.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Before implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("使用了"+o.getClass().getName()+"类的"+method.getName()+"方法");
    }
}

4.beans配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns: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.cjp.service.UserServiceImpl"/>
   <bean id="before" class="com.cjp.log.Before"/>
   <bean id="after" class="com.cjp.log.After"/>

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.cjp.service.UserServiceImpl.*(..))"/>
        <aop:advisor advice-ref="after" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="before" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

5.测试

import com.cjp.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.select();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iokBA2bX-1652524609588)(D:\Desktop\学习笔记\图片\image-20220511174555953.png)]

方式二:使用自定义类来实现AOP[主要是切面定义]

自定义一个类:

package com.cjp.diy;

public class DiyAdvance {
    public void before(){
        System.out.println("========方法执行前========");
    }
    public void after(){
        System.out.println("========方法执行后========");
    }
}

配置:

	<!--方式二:-->
    <bean id="userService" class="com.cjp.service.UserServiceImpl"/>
    <bean id="diy" class="com.cjp.diy.DiyAdvance"/>
    <aop:config>
        <!--自定义切面-->
        <aop:aspect ref="diy">
            <!--切入点-->
            <aop:pointcut id="point" expression="execution(* com.cjp.service.UserServiceImpl.*(..))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

方式三:使用注解实现

新建一个切面类:

package com.cjp.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;

@Aspect
public class AnnotationAspect {
    @Before("execution(* com.cjp.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("=====方法执行前======");
    }

    @After("execution(* com.cjp.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("=====方法执行后======");
    }

    @Around("execution(* com.cjp.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("环绕前");
        Signature signature = pj.getSignature();//获得签名
        System.out.println(signature);
        Object proceed = pj.proceed();//执行方法
        System.out.println("环绕后");
    }


}

配置:

 	<!--注册bean-->
   <bean id="userService" class="com.cjp.service.UserServiceImpl"/>
    <bean id="aspect" class="com.cjp.diy.AnnotationAspect"/>
    <!--开启注解支持-->
    <aop:aspectj-autoproxy/>

12、整合Mybatis

步骤:

1.导入依赖

  • junit
  • mybatis
  • mysql数据库
  • spring相关的
  • aop植入
  • mybatis-spring
<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</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.sqlSession

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

    <!--使用Spring的数据源替换mybatis的配置 c3p0 dbcp druid
    这里我们是用Spring提供的JDBC-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--绑定Mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/cjp/mapper/UserMapper.xml"/>
     </bean>

    <!--sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用构造器注入,因为他没有setter方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.cjp.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>


</beans>

4.需要给接口加实现类

方式一:

package com.cjp.mapper;

import com.cjp.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> getUsers() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUsers();
    }
}

方式二:

package com.cjp.mapper;

import com.cjp.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> getUsers() {
        return getSqlSession().getMapper(UserMapper.class).getUsers();
    }
}

配置:

    <bean id="userList" class="com.cjp.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

5.将自己写的实现类注入Spring中

6.测试使用

	@Test
    public void test() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapperImpl userMapper = context.getBean("userMapper", UserMapperImpl.class);
        List<User> users = userMapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        
    }

13、声明式事务

1、回顾事务

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

事务的ACID原则:

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作一个资源,防止数据损坏
  • 持久性
  • 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中!

2、spring中的事务管理

  • 声明式事务:AOP
  • 编程式事务:需要在代码中进行事务的管理

1.搭建环境

引入事务约束

接口:

package com.cjp.mapper;

import com.cjp.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserMapper {
    List<User> getUsers();

    /*插入一个用户*/
    int addUser(User user);

    /*删除一个用户*/
    int delete(int id);
}

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="com.cjp.mapper.UserMapper">
    <select id="getUsers" resultType="user">
        select * from mybatis.user
    </select>

    <insert id="addUser" parameterType="user">
        insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

    <!--故意将delete写错-->
    <delete id="delete" parameterType="_int">
        deletes from mybatis.user where id=#{id}
    </delete>
</mapper>

实现类:

package com.cjp.mapper;

import com.cjp.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> getUsers() {
        User user = new User(1007, "迪丽热巴", "535321");
        addUser(user);
        delete(1006);
        return getSqlSession().getMapper(UserMapper.class).getUsers();
    }

    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    @Override
    public int delete(int id) {
        return getSqlSession().getMapper(UserMapper.class).delete(id);
    }
}

运行结果:虽然报错,但是还是将用户插入了数据库

2.配置事务

	<!--配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--结合AOP实现事务的植入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务-->
        <!--配置事务的传播特性 propagation-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入-->
    <aop:config>
        <aop:pointcut id="point" expression="execution(* com.cjp.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
    </aop:config>

运行结果:只要报错,就不会对更改数据库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值