IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring全面详解 -> 正文阅读

[Java知识库]Spring全面详解

一、Spring简介

1.什么是Spring

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

?Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。

2.Spring组成

?Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。

二、搭建Spring环境

1.创建maven-java项目

1.1导入依赖

<dependencies>
        <!--   spring-context依赖中关联了其他核心依赖     -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
 </dependencies>

1.2Spring配置文件

  • 位置: resources

  • 格式: xml

  • 名称: 一般叫做applicationContext.xml,beans.xml, spring-context.xml,app.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">

    
</beans>

1.入门演示-IOC

1.1IOC介绍

IOC: Inversion of control 控制反转,以前对象创建的控制权在自己,现在将控制权交给Spring,由Spring框架创建对象。

需求:有一接口UserService,有一实现类UserServiceImpl.使用接口直接调用方法让其执行.

1.1详细步骤

1.UserService接口

public interface UserService {
    void findUserById();
}

2.UserServiceImpl实现类实现接口UserService

public class UserServiceImpl implements UserService {
    @Override
    public void findUserById() {
        System.out.println("UserServiceImpl.findUserById()执行" );
    }
}

3.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">
    <!--  spring配置文件applicationContext.xml相当于是
        一个容器,在这里配置整个项目中所需要的对象
     -->

    <!-- 一个bean标签代表一个类,会创建该类对象
        class 是要交给Spring创建对象的类路径
        id   是创建完成后的对象名
     -->
    <bean id="userService" class="com.qf.service.impl.UserServiceImpl"/>
</beans>

4.测试类

public class TsetIOC {
    @Test
    public void test(){
        String path = "applicationContext.xml";
        // 根据配置文件创建出spring容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 从容器中取出对象(根据对象名获得对象,配置文件中的id)
        UserService userService = (UserService) context.getBean("userService");
        userService.findUserById();
    }
}

三、DI-依赖注入

依赖注入就是属性赋值。

1.入门演示-DI

需求:给UserServiceImpl类中的UserDao属性赋值

1.实现类UserServiceImpl实现UserService,并创建Dao对象,给属性提供set方法

public class UserServiceImpl implements UserService {
    // 创建Dao对象
    private UserDao userDao;
    // 给属性提供set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void findUserById() {
        System.out.println("UserServiceImpl.findUserById()执行" );
        userDao.findUserById();
    }
}

2.创建一个接口UserDao

public interface UserDao {
    void findUserById();
}

3.实现类UserDaoImpl实现接口UserDao

public class UserDaoImpl implements UserDao {
    @Override
    public void findUserById() {
        System.out.println("UserDaoImpl.findUserById");
    }
}

4.applicationContext.xml配置文件

<bean id="userService" class="com.qf.service.impl.UserServiceImpl">
        <!-- 给属性赋值(DI)
            1) 属性要有set方法
            2) 属性值是另一个类对象,所以需要使用ref引用另一个类的对象id
        -->
        <property name="userDao" ref="userDao"></property>
    </bean>

    <!--   创建一个UserDao对象  -->
    <bean id="userDao" class="com.qf.dao.impl.UserDaoImpl"/>

5.测试类

@Test
    public void test(){
        String path = "applicationContext.xml";
        // 根据配置文件创建出spring容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 从容器中取出对象(根据对象名获得对象)
        UserService userService = (UserService) context.getBean("userService");
        userService.findUserById();
    }

总结:依赖注入就是给属性赋值,Spring提供了两种方案,一种set方式赋值,另一种是构造方法赋值。

2.依赖注入-基本类型

1.创建实体类

public class User {

    private int id;
    private String username;
    private Date birthday;
    private double score;
    // set get...
} 

2.applicationContext.xml配置文件

 <bean id="user" class="com.qf.model.User">
        <!--
            一个property标签给一个属性赋值
            name 是类的属性名 value是属性值
        -->
        <property name="id" value="18"/>
        <property name="username" value="admin"/>
        <property name="score" value="99.9"/>
        <!-- 日期这里使用value赋值,且格式只能是yyyy/MM/dd格式 -->
        <property name="birthday" value="2000/01/01"/>
    </bean>

测试类:

  @Test
    public void test2(){
        String path = "applicationContext.xml";
        // 根据配置文件创建出spring容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 从容器中取出对象(根据对象名获得对象)
        User user = (User) context.getBean("user");
        System.out.println(user );
    }

3.依赖注入-容器

数组、List、Set、Map

1.创建实体类

public class User{
    // 容器类型
    private  String[] phones;
    private List<String> list;
    private Set<String> set;
    private Map<String,Integer> map;
    // set get
}

2.applicationContext.xml配置文件

 <bean id="user" class="com.qf.model.User">
        <!-- 数组 -->
        <property name="phones">
            <array>
                <value>110</value>
                <value>120</value>
                <value>119</value>
            </array>
        </property>

        <!-- List,会允许重复 -->
        <property name="list">
            <list>
                <value>奔驰</value>
                <value>奔驰</value>
                <value>宝马</value>
                <value>奥迪</value>
            </list>
        </property>

        <property name="set">
              <!-- Set,不允许重复 -->
            <set>
                <value>145平</value>
                <value>145平</value>
                <value>155平</value>
                <value>165平</value>
            </set>
        </property>

        <!--Map-->
        <property name="map">
            <map>
                <entry key="一" value="1"/>
                <entry key="二" value="2"/>
                <entry key="三" value="3"/>
            </map>
        </property>
    </bean>

3.测试类

   @Test
    public void test2(){
        String path = "applicationContext.xml";
        // 根据配置文件创建出spring容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 从容器中取出对象(根据对象名获得对象)
        User user = (User) context.getBean("user");
        System.out.println(user );
    }

4.自动注入

applicationContext.xml配置文件

<!--
        autowire 属性,spring会在自动给UseServiceImpl类中的属性赋值
        自动注入的方式:
            byName: 通过名字注入
                    是属性名跟当前容器中bean标签id一致,既可以自动注入
            byTyoe: 通过类型注入
                    需要给中属性赋值,会在当前容器根据类型找到后,自动赋值
                    与对象名无关.如果当前容器中有多个该类型的值,会赋值失败
     -->
    <bean id="userService" class="com.qf.service.impl.UserServiceImpl" autowire="byType"/>

    <bean id="userDao1" class="com.qf.dao.impl.UserDaoImpl"/>

????????总结

????????自动注入的两种方式:

  • byName: 通过属性名和容器中对象名一致,即可自动注入
  • byType: 属性类型和容器中对象的类型一致,即可自动注入

四、注解实现IOC-DI

上面我们都是使用xml配置实现IOC和DI,以后将使用注解实现IOC和DI,即XML中不再配置很多标签了。

1.常用注解

注解作用被替代标签位置
@Component创建对象<bean>类上
@Controller创建对象<bean>控制层的类上
@Service创建对象<bean>业务层的类上
@Repository创建对象<bean>持久层的类上
@Value给基本类型属性赋值<property>属性上
@Autowired给引用类型属性赋值autowired的属性属性上

注意:@Component、@Controller、@Service、@Repository都是用来创建对象,只不过建议是在相应的位置使用相应的注解。

2.注解使用演示1(注解赋值)

需求:Teacher类,使用注解来创建Teacher类对象,以及给对象属性赋值。

1.创建Teacher实体类

package com.qf.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;

@Component // 取代<bean>,默认对象名就是类名小写
public class Teacher {
    @Value("20") // 取代<property>
    private int age;

    @Value("老王")
    private String name;

    @Value("2020/01/01")
    private Date birthday;

    //  set get toString
}

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

    <!--
        开启注解扫描,即让注解生效
     -->
    <context:component-scan base-package="com.qf"/>
</beans>

3.测试类

 @Test
    public void test5(){
        String path = "applicationContext3.xml";
        // 根据配置文件创建出spring容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);

        // 从容器中取出对象(默认是类名小写)
        Teacher teacher = (Teacher) context.getBean("teacher2");;
        System.out.println(teacher );
    }

3注解使用演示2(Service注入Dao)

需求:UserServiceImpl注入UserDao属性。

1.UserDaoImpl实现UserDao接口

@Repository  // 创建对象,取代<bean>
public class UserDaoImpl implements UserDao {
    @Override
    public void findUserById() {
        System.out.println("UserDaoImpl.findUserById");
    }
}

2.UserServiceImpl实现UserService接口

@Service  // 创建对象,取代<bean>
public class UserServiceImpl implements UserService {
    @Autowired  // 自动注入,按照类型注入byType
    private UserDao userDao;

    @Override
    public void findUserById() {
        System.out.println("UserServiceImpl.findUserById()执行" );
        userDao.findUserById();
    }
}

3.applicationContext.xml开启注解

    <!-- 开启注解扫描,即让注解生效 -->
    <context:component-scan base-package="com.qf"/>

按类型注入多个同类型,注入失败怎么解决

@Service
public class UserServiceImpl implements UserService {

    // 创建Dao对象
    @Autowired  // 自动注入,按照类型注入
    // 当同类型的对象有多个时,无法自动注入,需要手动指定注入哪个对象
    // 使用@Qualifier指定注入的对象名
    @Qualifier("userDaoImpl2")
    private UserDao userDao;
    // ...   
}

五、代理模式

1.代理介绍

简介:

代理就是一个中介,不仅仅可以实现某种目的还可以加上额外的操作的方式。

作用:

实现对目标对象原有的功能增强,即扩展目标对象的功能方法,并且不会修改原有代码。

分类:

  • ?静态代理,在运行前,通过编写代码的方式生成代理类
  • ?动态代理,在运行后,通过反射机制生成代理类

2.静态代理

静态代理就是:一个代理只能做一件事.做其他事情,需要再创建新代理.。

1)代理者和被代理者都实现相同的接口

2)代理者包含被代理者的对象

3)创建代理对象时传入被代理对象

4)代理者执行方法时,会调用被代理者的方法,同时扩展新的功能

2.1静态代理实例

需求:实现房东租房

1.创建接口

public interface FangDong {
    void zufang();
}

2.被代理者实现接口

public class FangdongImpl implements FangDong {
    @Override
    public void zufang() {
        System.out.println("房东租房..." );
    }
}

3.代理者实现接口

public class FangdongProxy {

    // 目标对象
    private FangDong fangDong;
    public FangdongProxy(FangDong fangDong){
        this.fangDong = fangDong;
    }
    void zufang(){
        // 前置增强
        System.out.println("前:发传单,找客源" );
        // 房东租房
        fangDong.zufang();
        // 后置增强
        System.out.println("后:签合同" );
    }
}

4.测试

    public static void main(String[] args) {// 开始租房
        // 找代理
        FangdongProxy proxy = new FangdongProxy(new FangdongImpl( ));
        // 真正租房
        proxy.zufang();
    }

3.动态代理

动态代理会动态的为目标类产生代理对象.动态代理有两种实现方案:

  1. JDK动态代理,只能代理接口.即目标类要有接口
  2. CGLIB动态代理,可以代理接口,也可以代理类,目录类可以有接口,也可以没有接口

3.1JDK动态代理

JDK代理,是Java自有技术无需导包

需求:使用动态代理技术,动态的产生房东代理对象,汽车厂商的代理

1.JDK代理实现InvocationHandler接口

public class JDKProxy implements InvocationHandler {
    // 目标类
    private Object target;

    // 指定目标对象
    public JDKProxy(Object target){
        this.target  = target;
    }
    /**
     * @param proxy 被代理对象
     * @param method 目标方法
     * @param args   目标方法的参数
     * @return       目标方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 目标方法前:
        System.out.println("前置增强" );
        // 目标方法执行
        Object obj = method.invoke(target,args);
        System.out.println("后置增强" );
        return obj;
    }
}

2.测试

 public static void main(String[] args) {
        // 目标类的类加载器
        ClassLoader classLoader = FangdongImpl.class.getClassLoader( );
        // 目标类的实现的所有接口
        Class<?>[] interfaces = FangdongImpl.class.getInterfaces( );
        // 目标方法执行处理器
        JDKProxy handler = new JDKProxy(new FangdongImpl( ));
        /**
         * 参数1: 目标类的类加载器
         * 参数2: 目标类的所实现的所有接口
         * 参数3:  自己实现的目标方法处理器
         */
        FangDong fangDong = (FangDong) Proxy.newProxyInstance(classLoader, interfaces, handler);
        fangDong.zufang();
    }

总结:动态代理,会动态产生目标类的代理对象,JDK的动态代理,目标必须有接口。

3.2CGLIB动态代理

CGLIB动态代理技术,又叫字节码增强.动态产生代理对象,可以代理接口也可以代理实现类.CGLIB是第三方技术,spring框架中已经整合了cglib的技术,所以只需导入spring-aop的依赖即可。

需求:使用动态代理技术,动态的产生房东代理对象,汽车厂商的代理

1.CGLIB代理实现MethodInterceptor接口

public class MyCglibInterceptor implements MethodInterceptor {
    // cglib的增强器
    private Enhancer enhancer = new Enhancer();
    // 创建拦截器时,指定目标类的字节码
    public MyCglibInterceptor(Class clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
    }
    // 提供一个获得代理对象的方法
    public Object createProxyBean(){
        return enhancer.create();
    }
    /**
     * @param target 目标对象
     * @param method
     * @param args   目标方法的参数
     * @param methodProxy 目标方法的代理对象
     * @return 目标方法的返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 目标方法前:
        System.out.println("前置增强:权限校验,或者事务开启" );
        // 目标方法执行
        Object ret = methodProxy.invokeSuper(target,args);
        // 目标方法前:
        System.out.println("后置增强:日志记录,或者事务提交" );
        return ret;
    }
}

2.测试

 public static void main(String[] args) {
        // 此处,只需要将其他类字节码文件传入此处
        // 即可得到其他类的代理对象
        MyCglibInterceptor interceptor = new MyCglibInterceptor(CarFactoryImpl.class);
        CarFactoryImpl carFactory = (CarFactoryImpl) interceptor.createProxyBean( );
        carFactory.saleCar();

    }

总结:CGLIB动态代理,会动态的给类产生代理对象,目标类可以没有接口,也可以有接口,都可以代理。

3.3总结

代理的目的: 将目标方法功能增强.

代理的方式: 静态代理和动态代理

什么区别:

  • 静态代理: 每个类都需要自己创建代理对象,一个代理只能代理一个类
  • 动态代理: 给每个类动态产生代理对象.(按需产生)

动态代理如何实现:

  • jdk的动态代理: jdk动态代理只能代理接口(目标类必须有接口)
  • cglib的动态代理:可以代理接口,也可以代理类(目标类可以有接口,也可以没接口)

六、AOP编程

1.AOP介绍

aop:aspect oriented programming(面向切面编程),它是对一类对象或所有对象编程。

? ? ? ? 核心:在不增加代码的基础上,还增加新功能

理解:

面向切面:其实就是,把一些公共的“东西”拿出来,比如说,事务,安全,日志,这些方面,如果你用的到,你就引入。

面向切面编程的作用:

将项目中与核心逻辑无关的代码横向抽取成切面类,通过织入作用到目标方法,以使目标方法执行前后达到增强的效果。

优点:

  • 可以对业务逻辑的各个部分进行隔离
  • 抽取代码,复用,提供效率
  • 减少耦合
  • 利于代码扩展

AOP术语:

  • 目标类(Target): 被代理的类
  • 连接点(JoinPoint): 目标类中准备被切入的方法
  • 切入点(Pointcut): 真正执行的目标方法
  • 切面(Aspect) : 切面中定义中增强的方法
  • 增强(Advice): 也叫通知,就是在目标方法执行前/后的方法
  • 织入(Weaving): 将增强作用到切入点的过程

2.AOP分类

5中通知的分类:

  • 前置通知(Before Advice):在目标方法被调用前调用通知功能,场景:一般用来做权限校验

  • 后置通知(After Advice):在目标方法被调用之后调用通知功能,场景: 释放资源,或者记录日志

  • 返回通知(After-returning):在目标方法成功执行之后调用通知功能,场景:数据库事务

  • 异常通知(After-throwing):在目标方法抛出异常之后调用通知功能,场景:得到目标方法返回值再处理

  • 环绕通知(Around):把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能。? 场景:可以获得目标方法的异常信息,用于记录日志,或者进行异常拦截

3.入门演示(步骤)

  • 依赖spring-aop.jar

  • 创建所需UserService和UserServiceImpl

  • 创建切面类

  • 配置文件配置切面

  • 测试

1.加入依赖:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>

2.创建接口

public interface UserService {
    void queryAllAdmin();

    void addAdmin();
}

3.创建实现类

public class UserServiceImpl implements UserService{
    @Override
    public void queryAllAdmin() {
        System.out.println("UserServiceImpl中queryAllAdmin执行了");
    }
    @Override
    public void addAdmin() {
        System.out.println("UserServiceImpl中addAdmin执行了");
    }
}

4.创建切面类

public class MyAspect {
    /**
     * 环绕通知
     * @param joinPoint
     */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //目标方法前
        System.out.println("前置增强:开启事务");
        //目标方法执行
        Object proceed = joinPoint.proceed();
        //目标方法执行后
        System.out.println("后置增强:提交事务");
        return proceed;
    }

    /**
     * 前置通知
     * @param joinPoint
     */
    public void befor(JoinPoint joinPoint){
        Object target = joinPoint.getTarget();
        System.out.println("前置增强,获得目标类对象:"+target);
        Signature signature = joinPoint.getSignature();
        System.out.println("前置增强,获得目标方法:"+signature);
        String name = signature.getName();
        System.out.println("前置增强,获得目标方法名字:"+name);
        System.out.println("前置增强:权限校验");

    }

    /**
     * 后置通知
     * @param joinPoint
     */
    public void after(JoinPoint joinPoint){
        //应用场景:还可以做一些关流,释放资源的动作
        System.out.println("后置通知:记录执行的日志");
    }

    /**
     * 环绕通知1
     * @param joinPoint:目标方法
     * @return
     */
    public Object around1(ProceedingJoinPoint joinPoint) throws Throwable {
        //目标执行前
        System.out.println("环绕-前置增强:开启事务");
        //目标执行
        Object proceed = joinPoint.proceed();
        //目标执行后
        System.out.println("环绕-后置增强:提交事务");
        return proceed;
    }

    /**
     * 后置返回通知
     * @param ret1:返回的参数
     * @return
     */
    public Object afterReturn(Object ret1){
        System.out.println("后置返回通知:"+ret1);
        return ret1;
    }

    /**
     * 异常处理通知
     * @param e
     */
    public void MyThrow(Exception e){
        //可以做全局异常处理,记录异常信息到日志
        System.out.println("异常通知,获得异常信息"+e.getMessage());
    }
}

4.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--创建目标类-->
    <bean id="userService" class="com.ymk.service.UserServiceImpl"/>
    
    <!--创建切面类对象-->
    <bean id="myAspect" class="com.ymk.aspect.MyAspect"/>
    
    <!--织入-->
    <aop:config>
        
        <!--抽取出来,方便后边调用-->
        <aop:pointcut id="p1" expression="execution(* com.ymk.service.*.*(..))"/>
        
        <!--配置切面,引用自定义切面对象-->
        <aop:aspect ref="myAspect">
            
            <!--配置环绕通知-->
            <aop:around method="around" pointcut-ref="p1"/>
            
            <!--配置前置通知-->
            <aop:before method="befor" pointcut-ref="p1"/>
            
            <!--配置后置通知-->
            <aop:after method="after" pointcut-ref="p1"/>
            
            <!--配置环绕通知-->
            <aop:around method="around1" pointcut-ref="p1"/>
            
            <!--配置后置返回通知
                returning指定增强方法的参数名ret
            -->
            <aop:after-returning method="afterReturn" pointcut-ref="p1" returning="ret1"/>
            
            <!--配置异常通知
                throwing指定增强方法的参数名
            -->
            <aop:after-throwing method="MyThrow" pointcut-ref="p1" throwing="e"/>
         </aop:aspect>
    </aop:config>
</beans>

4.AOP注解

4.1注解开发AOP

bean id="" class="目标类路径"——> @Service

bean id="切面对象" class="切面类路径" ——> @Component

aop:confing

aop:aspect ref="切面对象" ——> @Aspect

aop:before ——>@Before

aop:after ——>@After

aop:pointcut ——>@Pointcut

4.2AOP注解演示

1.创建接口

public interface UserService {
    void findUserById();
}

2.UserServiceImpl实现接口UserService

@Service // 让spring创建对象,将该类交给Spring托管
public class UserServiceImpl implements UserService {

    @Override
    public void findUserById() {
        System.out.println("com.qf.service.UserServiceImpl.findUserById()");
    }
}

3.切面类

@Component//加注解不用写bean标签
@Aspect//声明这是个切面
public class MyAspect {
    /**
     * 将表达式抽取出来,方便复用
     */
    @Pointcut("execution(* com.ymk.service.*.*(..))")
    public void pointcut() {
    }

    /**
     * 前置通知,其中写的是切入点表达式的方法名,注意不要忘了括号()
     */
    //@Before注解里写表达式
    @Before("pointcut()")
    public void myBefore() {
        System.out.println("前置增强:这是前置通知");
    }

    /**
     * 后置通知
     */
    @After("pointcut()")
    public void myAfter(JoinPoint joinPoint) {
        System.out.println("后置增强:这是后置增强" + joinPoint.getSignature().getName());
    }

    /**
     * 环绕通知
     */
    @Around("pointcut()")
    public void myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前置增强:开启事务");
        Object proceed = joinPoint.proceed();
        System.out.println("后置增强:提交事务");
    }

}

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

    <!-- 扫描注解使其生效 -->
    <context:component-scan base-package="com.qf"/>

    <!-- 开启AOP的自动代理配置 -->
    <aop:aspectj-autoproxy/>
</beans>

5.测试

   public static void main(String[] args) {
        // 获得容器对象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从容器获得对象,对象名一定是类名首字母小写
        UserService userService = context.getBean("userServiceImpl", UserService.class);

        // 执行目标方法,目标方法前后都会执行增强方法
        userService.findUserById();
    }

七、MyBatis和Spring框架整合

1.演示

1.1加入依赖

    <dependencies>

        <!--—————————mysql架包—————————-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>

        <!--————————mybatis架包————————-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!--————————log4j日志架包————————-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>

        <!--————————加入servlet依赖(servlet的jar)————————-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>

        <!--———————jsp的依赖(jsp相关的jar加进来)————————-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>

        <!--——————注解@Test测试类架包——————-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--——————逆向工程架包——————-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>

        <!--——————spring-context依赖中关联了其他核心依赖——————-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>

        <!--——————spring和mybatis整合时,需要的架包——————-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!--————————导入aop依赖————————-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>

        <!--————————导入切面aspect依赖————————-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>

        <!--——————spring事务—————-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.14.RELEASE</version>
        </dependency>

        <!--——————spring操作数据库JDBC——————-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.14.RELEASE</version>
        </dependency>

        <!--——————druid阿里的连接池——————-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <!--——————分页插件—————-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.3.0</version>
        </dependency>
    </dependencies>

1.2db.properties文件配置

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bank?useSSL=false
jdbc.username=root
jdbc.password=123456
# 配置初始化大小、最小、最大
jdbc.initialSize=5
jdbc.minIdle=3
jdbc.maxActive=20
#配置获取连接等待超时的时间
jdbc.maxWait=0
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
jdbc.timeBetweenEvictionRunsMillis=600000
#配置一个连接在池中最小生存的时间,单位是毫秒
jdbc.minEvictableIdleTimeMillis=300000

1.3mybatis-config.xml文件配置

<!-- 根标签 -->
<configuration>
    <!-- 此处大部分的配置,都可以交给Spring处理 -->
    <!--——————给类起别名,路径为包直接扫描包,不用每次配置——————-->
    <typeAliases>
        <package name="com.qf.model"/>
    </typeAliases>
</configuration>

1.4applicationContext.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--—————开启注解扫描,即让注解生效—————-->
    <context:component-scan base-package="com.ymk"/>

    <!--—————开启AOP自动代理配置—————-->
    <aop:aspectj-autoproxy/>

    <!--———————读取db.properties———————-->
    <context:property-placeholder location="classpath:db.properties"/>

    <!--—————1 druid数据源 实例化druid—————-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

        <!--—————配置初始化大小、最小、最大——————-->
        <property name="initialSize" value="${jdbc.initialSize}"/>
        <property name="minIdle" value="${jdbc.minIdle}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
        <!--——————配置获取连接等待超时的时间———————-->
        <property name="maxWait" value="${jdbc.maxWait}"/>
        <!--——配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒——— -->
        <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
        <!--————配置一个连接在池中最小生存的时间,单位是毫秒————-->
        <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
        <property name="testWhileIdle" value="true"/>
        <!--————这里建议配置为TRUE,防止取到的连接不可用—————-->
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="false"/>

    </bean>

    <!--—————2 创建Mybatis的工厂对象——————-->
    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--————————设置数据库连接池———————— -->
        <property name="dataSource" ref="dataSource"/>
        <!--—————加载mybatis主配置文件  classpath 表示classes目录所在路径—————-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--————————加载映射文件———————— -->
        <property name="mapperLocations" value="classpath:com/ymk/mapper/*.xml"/>
    </bean>
    <!--—————SqlSessionFactoryBean具体加载那个接口,adminDao,讲接口代理对象实例化出来
        spring就是依赖控制反转将对象创建出来的——————-->
    <!--———————3设置Mybatis的映射接口 ———————-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!--——设置映射接口所在包,会将mapper下所有的接口实例化出一个对象,不用sqlSession.getMapper了——-->
        <property name="basePackage" value="com.ymk.mapper"></property>
    </bean>

</beans>

1.5创建UserService接口和UserServiceImpl实现类

public interface UserService {
    User findUserById(int id);
}

@Service
public class UserServiceImpl implements UserService {
    // 设置Dao属性
    @Autowired // 自动注入Mapper
    private UserMapper userMapper;

    @Override
    public User findUserById(int id) {
        User user = userMapper.findUserById(id);
        return user;
    }
}

1.6UserMapper.java和UserMapper.xml

public interface UserMapper {
    User findUserById(int id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.mapper.UserMapper">

    <select id="findUserById" parameterType="int" resultType="User">
        select * from user where id = #{id}
    </select>
</mapper>

1.7测试

public class TestSpringMybatis {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService service = context.getBean("userServiceImpl", UserService.class);
        User user = service.findUserById(51);
        System.out.println(user);
    }
}

2.Spring整合Mybatis后Log4j不生效问题

解决方法:

将log4j依赖更新为log4j12依赖

        <!--————————log4j日志架包————————-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>

3.分页插件

分页插件作用: 可以自动完成分页功能。

以前需要自己在SQL中拼接limit语句,而且需要自己完成count()计算.

现在使用了分页插件,只需要正常查询全部数据,不用考虑关于分页的limit拼接问题,和count的数据条数等问题,插件全部搞定。

1.加入依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.0</version>
</dependency>

2.将分页插件的配置放在applicationContext.xml的SqlSessionFactory中

        <!-- 设置分页插件 -->
        <property name="plugins">
            <set>
                <!-- 创建分页插件对象,其实是一个拦截器 -->
                <bean class="com.github.pagehelper.PageInterceptor">
                    <!-- 给对象指定属性 -->
                    <property name="properties">
                        <props>
                            <!-- 指定数据库类型 -->
                            <prop key="helperDialect">mysql</prop>
                        </props>
                    </property>
                </bean>
            </set>
        </property>

3.创建UserService接口和UserServiceImpl实现类

public interface UserService {
    List<User> findAll();
}
@Service
public class UserServiceImpl implements UserService {
    // 设置Dao属性
    @Autowired
    private UserMapper userMapper;
    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }
}

4.创建UserMapper.java

public interface UserMapper {
    List<User> findAll();
}

5.创建UserMapper.xml

<select id="findAll" resultType="User">
        select * from user
    </select>

6.在代码中使用分页功能

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService service = context.getBean("userServiceImpl", UserService.class);
        // 设置分页
        PageHelper.startPage(2,2);

        // 查询全部
        List<User> all = service.findAll( );
        for (User user : all) {
            System.out.println(user );
        }
        // 将查询返回的集合,交给分页插件,返回给所有分页数据
        PageInfo<User> pageInfo = new PageInfo<>(all);
        System.out.println(pageInfo );
    }

底层原理:

拦截Mybatis发出SQL语句,自动拼接Limit 语句,完成分页语句.另外还会发出SELECT count(0) FROM user 计算数据条数。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 00:38:26  更:2022-09-30 00:39:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 5:08:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码