一、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配置文件  
<?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.动态代理 
 
 动态代理会动态的为目标类产生代理对象.动态代理有两种实现方案:  
 - JDK动态代理,只能代理接口.即目标类要有接口
 - 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.入门演示(步骤) 
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 计算数据条数。 
                
        
        
    
  
 
 |