0
点赞
收藏
分享

微信扫一扫

(sg)08.Spring笔记

四月Ren间 2022-04-19 阅读 39

一、@Configuration和@Component的区别

package com.qfedu.demo.config;

import com.qfedu.demo.model.Author;
import com.qfedu.demo.model.Book;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
//@Component
public class BookConfig {
    /**
     * 向 Spring 容器中注册一个 Author 对象
     * @return
     */
    @Bean
    Author author() {
        Author author = new Author();
        author.setName("罗贯中");
        author.setAge(80);
        return author;
    }

    /**
     * 向 Spring 容器注册一个 Book 对象
     * @return
     */
    @Bean
    Book book() {
        Book book = new Book();
        book.setName("三国演义");
        /**
         * 由于 author 方法上有一个 @Bean 注解,所以当这里去调用 author 方法的时候,Spring 会先去 Spring 容器中查看容器中是否存在一个 author 对象,如果存在,则直接使用,那么此时就不会真正的去执行 author 方法了。
         */
        //如果类上的注解是 @Component,而不是 @Configuration,那么此时 author 方法会被直接调用(不会先去 Spring 容器中查找了)
        book.setAuthor(author());
        return book;
    }

    @Bean
    Author author01() {
        Author author = new Author();
        author.setAge(55);
        author.setName("曹雪芹");
        return author;
    }

    /**
     * 可以直接在方法中添加一个 Author 参数,book01 方法并不是我们自己去调用的,这个方法是 Spring 调用的,那么 Spring 在调用的时候,会发现这个方法需要一个 author 参数,那么 Spring 会自动的去检查 Spring 容器中是否存在一个 Author 对象,如果存在,则直接在这里使用。
     *
     * 但是我们这里情况特殊,因为我们有两个 author 对象,我们可以通过注解告诉 Spring 容器这里需要的是哪个 author 对象
     *
     * @Qualifier("author01") 注解表示告诉 Spring 容器,我这里需要的 author 名为 author01。
     * 当然,如果 Spring 容器中,本来就只有一个 Author 对象,那么这里就不需要注解了。
     * @param author
     * @return
     */
    @Bean
    Book book01(@Qualifier("author01") Author author) {
        Book book = new Book();
        book.setName("红楼梦");
        book.setAuthor(author);
        return book;
    }
}

一、spring静态工厂模式

//静态工厂模式
public class OkHttpFactory {
    public static OkHttpClient okHttpClient(){
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(5,TimeUnit.SECONDS)
                .build();
        return okHttpClient;
    }
}

xml

<!--    静态工厂-->
<!--    因为是静态方法,所以可以直接调用,将来他会调这个方法,获取okHttpClient类,并且把它注册到spring容器中-->
    <bean class="com.qf.demo.OkHttpFactory" factory-method="okHttpClient" id="okHttpClient">
    </bean>

一、实例化工厂模式


//实例化工厂模式
public class OkHttpFactory2 {
    public OkHttpClient okHttpClient(){
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(5,TimeUnit.SECONDS)
                .build();
        return okHttpClient;
    }
}

xml

<!--    实例化工厂-->
<!--    因为不是静态的方法,所以要有这个对象才可以调用方法-->
<!--    1.首先要有这个对象-->
    <bean class="com.qf.demo.OkHttpFactory2" id="okHttpFactory2"></bean>
<!--    2.通过对象去调用方法-->
    <bean class="okhttp3.OkHttpClient" id="okHttpClient2" factory-bean="okHttpFactory2" factory-method="okHttpClient"></bean>

一、factoryBean

package com.qf.factoryBean;

import okhttp3.OkHttpClient;
import org.springframework.beans.factory.FactoryBean;

import java.util.concurrent.TimeUnit;

/**
 * 这是一个spring官方提供的工厂类
 */
public class OkHttpClientFactoryBean implements FactoryBean<OkHttpClient> {
    /**
     * 返回真正的工厂对象,对我们来说,返回的就是应该是一个OkHttpClient实例
     * @return
     * @throws Exception
     */
    public OkHttpClient getObject() throws Exception {
        return new OkHttpClient.Builder()
                .readTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(5,TimeUnit.SECONDS)
                .build();
    }

    /**"
     * 放回实例的类型,对我们来说,放回的就是OkHttpClient实例
     * @return
     */
    public Class<?> getObjectType() {
        return OkHttpClient.class;
    }

    /**
     * 放回的实例,是否是单例
     * @return
     */
    public boolean isSingleton() {
        return true;
    }
//    factorybean用来提供实例的类

}

xml

<!--注意,这个地方,虽然我们写class是OkHttpClientFactoryBean,但是spring容器自动检测该类是一个FactoeyBean实例,
所有最终注册Spring容器对象是该类中的getObject方法的返回值-->
    <bean class="com.qf.factoryBean.OkHttpClientFactoryBean" id="okHttpClient" />

一、引言

EJB


1.1 原生web开发中存在哪些问题?

二、Spring框架


2.1 概念

2.2 访问与下载

三、Spring架构组成


Spring架构组成
GroupIdArtifactId说明
org.springframeworkspring-beansBeans 支持,包含 Groovy
org.springframeworkspring-aop基于代理的AOP支持
org.springframeworkspring-aspects基于AspectJ 的切面
org.springframeworkspring-context应用上下文运行时,包括调度和远程抽象
org.springframeworkspring-context-support支持将常见的第三方类库集成到 Spring 应用上下文
org.springframeworkspring-core其他模块所依赖的核心模块
org.springframeworkspring-expressionSpring 表达式语言,SpEL
org.springframeworkspring-instrumentJVM 引导的仪表(监测器)代理
org.springframeworkspring-instrument-tomcatTomcat 的仪表(监测器)代理
org.springframeworkspring-jdbc支持包括数据源设置和 JDBC 访问支持
org.springframeworkspring-jms支持包括发送/接收JMS消息的助手类
org.springframeworkspring-messaging对消息架构和协议的支持
org.springframeworkspring-orm对象/关系映射,包括对 JPA 和 Hibernate 的支持
org.springframeworkspring-oxm对象/XML 映射(Object/XML Mapping,OXM)
org.springframeworkspring-test单元测试和集成测试支持组件
org.springframeworkspring-tx事务基础组件,包括对 DAO 的支持及 JCA 的集成
org.springframeworkspring-webweb支持包,包括客户端及web远程调用
org.springframeworkspring-webmvcREST web 服务及 web 应用的 MVC 实现
org.springframeworkspring-webmvc-portlet用于 Portlet 环境的MVC实现
org.springframeworkspring-websocketWebSocket 和 SockJS 实现,包括对 STOMP 的支持
org.springframeworkspring-jclJakarta Commons Logging 日志系统

四、自定义工厂


4.1 配置文件

userDAO=com.qf.dao.UserDAOImpl
userService=com.qf.service.UserServiceImpl

4.2 工厂类

/**
 * 自定义工厂
 */
public class MyFactory {
    private Properties properties = new Properties();
    public MyFactory(){}
    public MyFactory(String config) throws IOException {
        // 加载配置文件
        properties.load(MyFactory.class.getResourceAsStream(config));
    }
    // 获取对象
    public Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 获得类路径
        String classPath = properties.getProperty(beanName);
        if(classPath!=null){
            Class claz = null;
            // 反射:加载类对象
            claz = Class.forName(classPath);
            // 反射:获得对象
            return claz.newInstance();
        }
        return null;
    }
}

五、构建Maven项目


5.1 新建项目

使用IDEA打开已创建的文件夹目录

 

5.2 选择Maven目录

选择Maven项目

 

5.3 GAV坐标

GAV坐标

 

六、Spring环境搭建


6.1 pom.xml中引入Spring常用依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation=
         "http://maven.apache.org/POM/4.0.0 
          http://maven.apache.org/xsd/maven-4.0.0.xsd">
  
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>com.qf</groupId>
    <artifactId>hello-spring</artifactId>
    <version>1.0-SNAPSHOT</version>
​
    <dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
    </dependencies>
</project>

​6.2 创建Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   
</beans>

七、Spring工厂编码


public class MyClass{
    public void show(){
        System.out.println("HelloWorld");
    }
}
<!-- 配置实例(id:“唯一标识”  class="需要被创建的目标对象全限定名") -->
<bean id="mc" class="com.qf.spring.part1.factory.MyClass" />
public class TestFactory{
    /**
     * 程序中的对象都交由Spring的ApplicationContext工厂进行创建。
     */
    public static void main(String[] args){
        //1. 读取配置文件中所需创建的bean对象,并获得工厂对象
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
        //2. 通过id获取bean对象
        MyClass mc = (MyClass) ctx.getBean("mc");
        //3. 使用对象
        mc.show();
    }
}

八、依赖与配置文件详解


8.1 Spring依赖关系

Spring常用功能的Jar包依赖关系
  • 注意:Jar包彼此存在依赖,只需引入最外层Jar即可由Maven自动将相关依赖Jar引入到项目中。

8.2 schema

九、IoC(Inversion of Control )控制反转【重点


9.1 项目中强耦合问题

public class UserDAOImpl implements UserDAO{....}

public class UserServiceImpl implements UserService {
    // !!!强耦合了UserDAOImpl!!!,使得UserServiceImpl变得不稳健!!
    private UserDAO userDAO= new UserDAOImpl();
    @Override
    public User queryUser() {
        return userDAO.queryUser();
    }
    ....
}

9.2 解决方案

// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService {
    // !!!不再耦合任何DAO实现!!!,消除不稳健因素!!
    private UserDAO userDAO;
    // 为userDAO定义set/get,允许userDAO属性接收spring赋值
    //Getters And Setters
    @Override
    public User queryUser() {
        return userDAO.queryUser();
    }
    ....
}
<bean id="userDAO" class="com.qf.spring.part1.injection.UserDaoImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
    <!-- 由spring为userDAO属性赋值,值为id="userDAO"的bean -->
    <property name="userDAO" ref="userDAO"/>
</bean>

十、DI(Dependency Injection)依赖注入【重点

三种属性注入方式:

  • 构造方法注入

  • set 方法注入(推荐)

  • p名称空间注入(本质上还是 set 方法注入)

各种注入属性:

  • 基本数据类型,直接使用标签的 value 属性注入

  • 对象

    • 外部定义好一个对象,然后通过 ref 引用对象

    • 直接在需要的地方通过 bean 标签定义一个对象(局限性,定义好的 bean 无法复用)

  • List 集合:list

  • 数组:array

  • Map:map

  • Properties :props


10.1 概念

10.2 Set注入

10.2.1 定义目标Bean类型

public class User {
    private Integer id;
    private String password;
    private String sex;
    private Integer age;
    private Date bornDate;
    private String[] hobbys;
    private Set<String> phones;
    private List<String> names;
    private Map<String,String> countries;
    private Properties files;
    //Getters And Setters
}

10.2.2 基本类型 + 字符串类型 + 日期类型

<bean id="u1" class="com.qf.spring.part1.injection.User">
    <!--base field-->
    <property name="id" value="1001" />
    <property name="password" value="123456" />
    <property name="sex" value="male" />
    <property name="age" value="20" />
    <property name="bornDate" value="1990/1/1" /><!--注意格式"/"-->
</bean>

10.2.3 容器类型

<bean id="u1" class="com.qf.spring.part1.injection.User">   
    <!--Array-->
    <property name="hobbys">
        <array>
            <value>Run</value>
            <value>Swim</value>
            <value>Climb</value>
        </array>
    </property>
​
    <!--Set-->
    <property name="phones">
        <set>
            <value>13777777777</value>
            <value>13888888888</value>
            <value>13999999999</value>
        </set>
    </property>
​
    <!--List-->
    <property name="names">
        <list>
            <value>tom</value>
            <value>jack</value>
            <value>marry</value>
        </list>
    </property>
​
    <!--Map-->
    <property name="countries">
        <map>
            <entry key="CN" value="China" />
            <entry key="US" value="America" />
            <entry key="KR" value="Korea" />
        </map>
    </property>
    
    <!--Properties-->
    <property name="files">
        <props>
            <prop key="first">One</prop>
            <prop key="second">Two</prop>
            <prop key="third">Three</prop>
        </props>
    </property>
</bean>

10.2.4 自建类型

<!--次要bean,被作为属性-->
<bean id="addr" class="com.qf.spring.part1.injection.Address">
    <property name="position" value="北京市海淀区" />
    <property name="zipCode" value="100001" />
</bean>
​
<!--主要bean,操作的主体-->
<bean id="u2" class="com.qf.spring.part1.injection.User">
    <property name="address" ref="addr" /><!--address属性引用addr对象-->
</bean>
<!--次要bean,被作为属性-->
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
​
<!--主要bean,操作的主体-->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
    <property name="ud" ref="userDao" /><!--ud属性引用userDao对象-->
</bean>

10.3 构造注入【了解】

10.3.1 定义目标Bean类型

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
  
    //Constructors
    public Student(Integer id , String name , String sex , Integer age){
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

10.3.2 注入

 <!--构造注入-->
<bean id="u3" class="com.qf.zcg.spring.day1.t2.ioc.Student">
    <constructor-arg name="id" value="1234" /> <!-- 除标签名称有变化,其他均和Set注入一致 -->
    <constructor-arg name="name" value="tom" />
    <constructor-arg name="age" value="20" />
    <constructor-arg name="sex" value="male" />
</bean>

10.4 自动注入【了解】

public class UserServiceImpl implements UserService {
    private UserDAO userDAO;
    //Getters And Setters
    ....
}
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byName"></bean>

十一、Bean细节


11.1 控·制简单对象的单例、多例模式

<!--
    singleton(默认):每次调用工厂,得到的都是同一个对象。
    prototype:每次调用工厂,都会创建新的对象。
-->
<bean id="mc" class="com.qf.zcg.spring.day1.t1.basic.MyClass" scope="singleton" /> 
  • 注意:需要根据场景决定对象的单例、多例模式。

  • 可以共用:Service、DAO、SqlSessionFactory(或者是所有的工厂)。

  • 不可共用:Connection、SqlSession、ShoppingCart。

11.2 FactoryBean创建复杂对象【了解】

FactoryBean解决复杂对象创建

 11.2.1 实现FactoryBean接口

接口方法描述

 

  • 注意:isSingleton方法的返回值,需根据所创建对象的特点决定返回true/false。

  • 例如:Connection 不应该被多个用户共享,返回false。

  • 例如:SqlSessionFactory 重量级资源,不该过多创建,返回true。

11.2.2 配置spring-context.xml

配置与获取方式

11.2.3 特例

获取FactoryBean接口的实现类对象,而非getObject()所生产的对象。

十二、Spring工厂特性


12.1 饿汉式创建优势

12.2 生命周期方法

12.3 生命周期注解

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
​
@PostConstruct //初始化 
public void init(){
    System.out.println("init method executed");
}
​
@PreDestroy //销毁
public void destroy(){
    System.out.println("destroy method executed");
}

12.4 生命周期阶段

十三、代理设计模式


13.1 概念

功能分离

 

13.2 静态代理设计模式

静态代理

 

  • 代理类 = 实现原始类相同接口 + 添加辅助功能 + 调用原始类的业务方法。

  • 静态代理的问题

    • 代理类数量过多,不利于项目的管理。

    • 多个代理类的辅助功能代码冗余,修改时,维护性差。

13.3 动态代理设计模式

有两种实现方式:

  • 基于 JDK(不需要额外引入jar):被代理的对象存在接口。

  • 基于 cglib(需要引入外部jar):被代理的对象可以没有接口。

13.3.1 JDK动态代理实现(基于接口)

//目标
final OrderService os = new OrderServiceImpl();
//额外功能
InvocationHandler handler = new InvocationHandler(){//1.设置回调函数(额外功能代码)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
        System.out.println("start...");
        method.invoke(os, args);
         System.out.println("end...");
        return null;
    }
};
//2.创建动态代理类
Object proxyObj = Proxy.newProxyInstance(ClassLoader , Interfaces , InvocationHandler);

13.3.2 CGlib动态代理实现(基于继承)

final OrderService os = new OrderServiceImpl();
Enhancer cnh = new Enhancer();//1.创建字节码曾强对象
enh.setSuperclass(os.getClass());//2.设置父类(等价于实现原始类接口)
enh.setCallback(new InvocationHandler(){//3.设置回调函数(额外功能代码)
    @Override
    public Object invoke(Object proxy , Method method, Object[] args) throws Throwable{
        System.out.println("start...");
        Object ret = method.invoke(os,args);
        System.out.println("end...");
        return ret;
    }
});
OrderService proxy = (OrderService)enh.create();//4.创建动态代理类
proxy,createOrder();

十四、面向切面编程【重点

AOP 的实现:

选项spring-aspectsaspectj(首选)
实现类spring-aspectsaspectjweaver,aspectjrt
实现方式通过实现接口来定义通知通过方法+注解来实现通知

14.1 概念

14.2 AOP开发术语

14.3 作用

14.4 环境搭建

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       ">
</beans>

14.5 开发流程

package com.qf.aaron.aop.basic;
​
public interface UserService {
    public void save();
}
package com.qf.aaron.aop.basic;
​
public class UserServiceImpl implements UserService {
    public void save() {
        System.out.println("save method executed...");
    }
}

package com.qf.aaron.aop.basic;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
​
public class MyAdvice implements MethodBeforeAdvice { //实现前置通知接口
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before advice executed...");
    }
}

<!--原始对象-->
<bean id="us" class="com.qf.aaron.aop.basic.UserServiceImpl" />
​
<!--辅助对象-->
<bean id="myAdvice" class="com.qf.aaron.aop.basic.MyAdvice" />

<aop:config>
    <!--切点-->
    <aop:pointcut id="myPointCut" expression="execution(* save())" />
</aop:config>
<aop:config>
    <!--组装切面 -->
    <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" />
</aop:config>

14.6 AOP小结

14.7 通知类【可选】

前置通知:MethodBeforeAdvice
​
后置通知:AfterAdvice
​
返回通知:AfterReturningAdvice //有异常不执行,方法会因异常而结束,无返回值
​
异常通知:ThrowsAdvice
​
环绕通知:MethodInterceptor

14.8 通配切入点

<!--匹配参数-->
<aop:pointcut id="myPointCut" expression="execution(* *(com.qf.aaron.aop.basic.User))" />
<!--匹配方法名(无参)-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--匹配方法名(任意参数)-->
<aop:pointcut id="myPointCut" expression="execution(* save(..))" />
<!--匹配返回值类型-->
<aop:pointcut id="myPointCut" expression="execution(com.qf.aaron.aop.basic.User *(..))" />
<!--匹配类名-->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop.basic.UserServiceImpl.*(..))" />
<!--匹配包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop.basic.*.*(..))" />
<!--匹配包名、以及子包名-->
<aop:pointcut id="myPointCut" expression="execution(* com.qf.aaron.aop..*.*(..))" />

14.9 JDK和CGLIB选择

class DefaultAopProxyFactory{
    // 该方法中明确定义了 JDK代理和CGLib代理的选取规则
    // 基本规则是:目标业务类如果有接口则用JDK代理,没有接口则用CGLib代理
    public AopProxy createAopProxy(){...}
}

14.10 后处理器

常用后处理器

14.10.1 后处理器定义

 

/**
 * 定义bean后处理器
 * 作用:在bean的创建之后,进行再加工
 */
public class MyBeanPostProcessor implements BeanPostProcessor{
​
    /**
     * 在bean的init方法之前执行
     * @param bean  原始的bean对象
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后处理器 在init之前执行~~~"+bean.getClass());
        return bean;
    }
    /**
     * 在bean的init方法之后执行
     * @param bean  postProcessBeforeInitialization返回的bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后处理器 在init之后执行~~~"+bean.getClass());
        return bean;// 此处的返回是 getBean() 最终的返回值
    }
}

14.10.2 配置后处理器

<!-- 配置后处理器,将对工厂中所有的bean声明周期进行干预 -->
<bean class="com.qianfeng.beanpostprocessor.MyBeanPostProcessor"></bean>

14.10.3 bean生命周期

14.10.4 动态代理源码(了解)

// AbstractAutoProxyCreator是 AspectJAwareAdvisorAutoProxyCreator的父类
// 该后处理器类中的 wrapIfNecessary方法即动态代理生成过程
AbstractAutoProxyCreator#postProcessAfterInitialization(Object bean, String beanName){
    if (!this.earlyProxyReferences.contains(cacheKey)) {
        // 开始动态定制代理
        return wrapIfNecessary(bean, beanName, cacheKey);
    }
}

十五、Spring + MyBatis【重点


15.1 配置数据源

15.1.1 引入jdbc.properties配置文件

#jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456

15.1.2 整合Spring配置文件和properties配置文件

<!--spring-context.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       ">
​
    <!--配置文件参数化(参数占位符)-->
    <context:property-placeholder location="classpath:jdbc.properties" />
    
    <!--与PooledDataSource集成(二选一)-->
    <bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
        <property name="driver" value="${driverClass}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
​
    <!--与DruidDataSource集成(二选一)-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--基本配置-->
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</bean>

15.1.3 Druid连接池可选参数

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <!--基本配置-->
    <property name="driverClassName" value="${jdbc.driverClass}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
​
    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="${jdbc.init}"/>
    <property name="minIdle" value="${jdbc.minIdle}"/>
    <property name="maxActive" value="${jdbc.maxActive}"/>
​
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="60000"/>
​
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="60000"/>
​
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="300000"/>
</bean>

15.1.4 Druid监控中心

<!--web.xml-->
<servlet>
    <servlet-name>DruidStatView</servlet-name>
    <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>DruidStatView</servlet-name>
    <url-pattern>/druid/*</url-pattern>
</servlet-mapping>

15.1.5 测试监控中心

15.2 整合MyBatis

15.2.1 导入依赖

<!-- spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>
​
<!-- spring+mybatis集成依赖 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>

15.2.2 配置SqlSessionFactory

<!-- 工厂bean:生成SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 注入连接池 -->
    <property name="dataSource" ref="dataSource"></property>
    <!-- 注入dao-mapper文件信息 ,如果映射文件和dao接口 同包且同名,则此配置可省略-->
    <property name="mapperLocations">
        <list>
            <value>classpath:com/qf/spring/dao/*.xml</value>
        </list>
    </property>
    <!-- 为 dao-mapper文件中的实体 定义缺省包路径 
        如:<select id="queryAll" resultType="User"> 中 User类可以不定义包
    -->
    <property name="typeAliasesPackage" value="com.qf.entity"></property>
</bean>

15.2.3 配置MapperScannerConfigurer

<!-- mapperScannerConfigurer -->
<bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- dao接口所在的包  如果有多个包,可以用逗号或分号分隔 
        <property name="basePackage" value="com.a.dao,com.b.dao"></property>
    -->
    <property name="basePackage" value="com.qf.spring.dao"></property>
    <!-- 如果工厂中只有一个SqlSessionFactory的bean,此配置可省略 -->
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>

15.2.4 配置Service

<bean id="userService" class="com.qf.spring.service.UserServiceImpl">
    <!-- 注意ref中的值是对应DAO接口的首字母小写的接口名 -->
    <property name="userDAO" ref="userDAO"></property>
</bean>

十六、事务【重点


16.1 配置DataSourceTransactionManager

<!-- 1. 引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑 -->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

16.2 配置事务通知

<tx:advice id="txManager" transaction-manager="tx">
    <tx:attributes>
        <!--<tx:method name="insertUser" rollback-for="Exception" isolation="DEFAULT"    
                propagation="REQUIRED" read-only="false"/>-->
        <!-- 以User结尾的方法,切入此方法时,采用对应事务实行-->
        <tx:method name="*User" rollback-for="Exception"/>
        <!-- 以query开头的方法,切入此方法时,采用对应事务实行 -->
        <tx:method name="query*" propagation="SUPPORTS"/>
        <!-- 剩余所有方法 -->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

16.3 事务属性

16.3.1 隔离级别

16.3.1.1 概念

名称描述
default(默认值)(采用数据库的默认的设置) (建议)
read-uncommited读未提交
read-commited读提交 (Oracle数据库默认的隔离级别)
repeatable-read可重复读 (MySQL数据库默认的隔离级别)
serialized-read序列化读

16.3.1.2 特性

16.3.1.3 并发问题

问题描述
脏读一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止
不可重复读一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止
幻读一个事务内多次读取一张表中的相同内容,其结果不一致。serialized-read 可防止

16.3.2 传播行为

16.3.3 读写性

16.3.4 事务超时

16.3.5 事务回滚

16.4 编织

<aop:config>
    <aop:pointcut expression="execution(* com.qf.spring.service.UserServiceImpl.*(..))" id="pc"/>
    <!-- 组织切面 -->
    <aop:advisor advice-ref="txManager" pointcut-ref="pc"/>
</aop:config>

十七、注解开发


17.1 声明bean

// @Service说明 此类是一个业务类,需要将此类纳入工厂  等价替换掉 <bean class="xxx.UserServiceImpl">
// @Service默认beanId == 首字母小写的类名"userServiceImpl"
// @Service("userService") 自定义beanId为"userService"
@Service //声明bean,且id="userServiceImpl"
@Scope("singleton") //声明创建模式,默认为单例模式 ;@Scope("prototype")即可设置为多例模式
public class UserServiceImpl implements UserService {
    ...   
}

17.2 注入(DI)

@Service
public class UserServiceImpl implements UserService {
    
    @Autowired //注入类型为UserDAO的bean
    @Qualifier("userDAO2") //如果有多个类型为UserDAO的bean,可以用此注解从中挑选一个
    private UserDAO userDAO;
}
@Service
public class UserServiceImpl implements UserService {
    
    @Resource("userDAO3") //注入id=“userDAO3”的bean
    private UserDAO userDAO;
    /*
    @Resource //注入id=“userDAO”的bean
    private UserDAO userDAO;
    */
}
public class XX{
    @Value("100") //注入数字
    private Integer id;
    @Value("shine") //注入String
    private String name;
}

17.3 事务控制

//类中的每个方法都切入事务(有自己的事务控制的方法除外)
@Transactional(isolation=Isolation.READ_COMMITTED,propagation=Propagation.REQUIRED,readOnly=false,rollbackFor=Exception.class,timeout = -1)
public class UserServiceImpl implements UserService {
    ...
    //该方法自己的事务控制,仅对此方法有效
    @Transactional(propagation=Propagation.SUPPORTS)
    public List<User> queryAll() {
        return userDao.queryAll();
    }
    public void save(User user){
        userDao.save(user);
    }
}

17.4 注解所需配置

<!-- 告知spring,哪些包中 有被注解的类、方法、属性 -->
<!-- <context:component-scan base-package="com.qf.a,com.xx.b"></context:component-scan> -->
<context:component-scan base-package="com.qf"></context:component-scan>
    
<!-- 告知spring,@Transactional在定制事务时,基于txManager=DataSourceTransactionManager -->
<tx:annotation-driven transaction-manager="txManager"/>

17.5 AOP开发

17.5.1 注解使用

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
​
@Aspect // 声明此类是一个切面类:会包含切入点(pointcut)和通知(advice)
@Component //声明组件,进入工厂
public class MyAspect {
    // 定义切入点
    @Pointcut("execution(* com.qf.spring.service.UserServiceImpl.*(..))")
    public void pc(){}
    
    @Before("pc()") // 前置通知
    public void mybefore(JoinPoint a) {
        System.out.println("target:"+a.getTarget());
        System.out.println("args:"+a.getArgs());
        System.out.println("method's name:"+a.getSignature().getName());
        System.out.println("before~~~~");
    }
​
    @AfterReturning(value="pc()",returning="ret") // 后置通知
    public void myAfterReturning(JoinPoint a,Object ret){
        System.out.println("after~~~~:"+ret);
    }
    
    @Around("pc()") // 环绕通知
    public Object myInterceptor(ProceedingJoinPoint p) throws Throwable {
        System.out.println("interceptor1~~~~");
        Object ret = p.proceed();
        System.out.println("interceptor2~~~~");
        return ret;
    }
    
    @AfterThrowing(value="pc()",throwing="ex") // 异常通知
    public void myThrows(JoinPoint jp,Exception ex){
        System.out.println("throws");
        System.out.println("===="+ex.getMessage());
    }
}

17.5.2 配置

<!-- 添加如下配置,启用aop注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

十八、集成JUnit


18.1 导入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

18.2 编码

@RunWith(SpringJUnit4ClassRunner.class) //由SpringJUnit4ClassRunner启动测试
@ContextConfiguration("classpath:applicationContext.xml") //spring的配置文件位置
public class SpringTest{//当前测试类也会被纳入工厂中,所以其中属性可以注入
​
    @Autowired // 注入要测试的组件
    @Qualifier("userDAO")
    private UserDAO userDAO;
​
    @Test
    public void test(){
        // 测试使用userDAO
        userDAO.queryUser();
        ....
    }
}
举报

相关推荐

0 条评论