spring基础知识

0.总结

1.mybatis

  • 对jdbc的初步分装,MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

2.连接池c3p0,druid

负责数据库的连接,创建连接,释放连接。

​ 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。

主要是管理数据库连接的

  • C3P0 数据库连接池
    在使用了数据库连接池之后,在项目的实际开发中就不需要编写连接数据库的代码了,直接从数据源获得数据库的连接。
  • Druid 相对于其他数据库连接池的优点:

3.事务处理

​ 数据库的事务管理。保证数据库的正常运行。作用在数据源上。

1.ioc容器


  • 第一步通过xml配置,交代清楚bean的类和类的id还可以配置一些初始化的参数
    • 其中id是页面获取bean的主要方式。
  • 创建工厂类--> 通过反射创建对象(class.newInstance)

1.ioc接口

  1. ioc是个容器,本质就是一个对象的工厂

  2. spring提供了Ioc容器实现的两种接口

    1. BeanFactory spring内部使用,一般不提供开发人员使用。

    2. ApplicationContext:提供给开发人员使用,功能更加丰富。

    区别:前者bean在调用的时候创建对象,而后者加载配置文件就自动生成bean对象。

2.ioc具体操作

1.bean创建

  1. spring帮我们创建对象
  2. 由Spring帮我们注入属性

2.bean管理

  1. 基于xml方式创建对象,

    1. id唯一标识符
    2. class对象类的全路径
    3. name和id差不多。

    默认执行无参构造方法get/set函数。

    java在运行的时候和C++相同,如果没有任何构造函数,自动创建一个无参构造函数,如果有构造函数,不注入无参构造函数

  2. 基于xml注入属性

    <bean id="user" class="com.demo.spring5.User">
        <property name="name" value="1111"/>
    </bean>
    
  3. 有参数的构造:constructor-arg

    • name 属性名或者index:第一个参数(0开始)
    <bean id="user1" class="com.demo.spring5.User">
        <constructor-arg name="name" value="1111" />
        <constructor-arg index="0" value="1"/>
    </bean>
  1. p名称空间注入:本质无参加set

    xmlns:p="http://www.springframework.org/schema/p"
    <bean id="user2" class="com.demo.spring5.User" p:name="22"></bean>
    

1.如何注入特殊值

  1. 空值<null/>
  2. 特殊符号的注入
<property name="name">
    <null/>
</property>
<!--特殊符号的注入-->
<bean id="user3" class="com.demo.spring5.User">
    <property name="name" >
        <value><![CDATA[<<南京>>]]></value>
    </property>
</bean>

2.如何注入bean

包含内部bean和级联bean

  1. 创建service类和Dao类,

  2. 通过ref实现bean的内部注入。

    <!--联级bean-->
    <!-- bean中注入bean-->
    <bean id="userDao" class="com.demo.dao.UserDaoImp"/>
    <bean id="userService" class="com.demo.service.UserService">
        <property name="userDao" ref="userDao"/>
    	<!--也可以直接给userDao中的属性赋值,需要设置 userDao的get方法-->
        <property name="userDao.name"value="name"/> 
    </bean>
    
    <!--内部bean,在property里面加入bean-->
    <bean id="userService" class="com.demo.service.UserService">
        <property name="userDao">
        	<bean id="userDao" class="com.demo.dao.UserDaoImp"/>
        </property>
    </bean>
    

3.注入属性-内部bean和级联赋值

  1. 一对多关系:部门和员工
  2. 实体类之间表示一对多关系

3.基于xml注入集合属性

1.注入数组

2.注入list集合属和

3.注入mapper属性

<bean id="student" class="com.example.bean.Stu">
    <property name="courses">
        <array>
            <value>java</value>
            <value>sql</value>
        </array>
    </property>
    <property name="list">
        <list>
            <value>张三</value>
            <value>小三</value>
        </list>
    </property>
    <property name="map">
        <map>
            <entry key="Java" value="88"></entry>
            <entry key="C++" value="88"></entry>
        </map>
    </property>
    <property name="set">
        <set>
            <value>三好学生</value>
            <value>优秀共青团员</value>
        </set>
    </property>
</bean>

image

4.注入对象数组

<!--        给对象集合赋值-->
        <property name="coursesList">
            <list>
                <ref bean="course1"/>
                <ref bean="course2"/>
            </list>
        </property>

5.抽取集合

可以通过util工具抽取集合,为了多次使用

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

    <util:list id="bookList">
        <value>九阳申通</value>
        <value>易经</value>
    </util:list>
    <bean id="book" class="com.example.bean.Book">
        <property name="list" ref="bookList"></property>
    </bean>
</beans>
    

4.工厂bean

Spring中Bean可以分为两种,工厂bean普通bean

其中存在 这样的区别

  1. 普通bean:在配置文件定义中bean类型就是返回值类型
  2. 工厂bean:配置类型和返回类型可以不一样。

1.单实例和多实例

解释:正常情况下是单实例,工厂中的bean对象只有一个,不论在那个地方拿取bean使用,而多实例则是每次拿去 的bean都会重新创建,用完自动回收。

scope属性:@Scope

  1. prototype:多实例懒加载
  2. singleton:单实例,
  3. request:每次创建之后会自动放到request中
  4. seesion:每次创建之后会自动放到seesion域中

2.自定义工厂bean

​ 和多实例的效果相同

​ 一般而言,在xml中注册的bean的实例接收类型只能是预设类其子类或者是继承接口的关系,工厂bean就是注册一个工厂,获取的类型是个bean的产品。

特点:

  1. 继承FactoryBean<Coure>接口
  2. 传入产品类进行接受
public class MyBean implements FactoryBean<Course> {
    
    @Override
    public Course getObject() throws Exception {
        Course coursec = new Course();
        coursec.setName("abc");
        return coursec;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

5.bean的生命周期

从对象的创建到对象的销毁,有哪些过程呢??

  1. 创建bean实例(无参构造)
  2. 为bean的属性注入值(set方法)
  3. 调用bean中初始化的方法(需要配置)
  4. bean可以使用了(对象的获取)
  5. 容器的关闭,bean的销毁
    <bean id="book" class="com.example.bean.Book" init-method="Init" destroy-method="destory">
        <property name="list" ref="bookList"></property>
    </bean>

image

此外还可以有多余的两步,在初始化的前后设置前置和后置处理器。

bean的前后置处理器

指的是在初始化前后加入前后置处理器BeanPostProcessor

​ bean实际可以扩充成七步

  1. 设置前后置处理器
  2. 配置前后置处理器
    1. 可以直接在xml中将后置处理器注册成bean,这个可以处理器对所有的bean有效
public class MyBeanPost implements BeanPostProcessor{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

    <bean id="myBeanProcess" class="com.example.bean.MyBeanPost"/>

image

6.自动注入

自动注入有两张方法: byName,byTye,反别是更具bean的id和class去注入属性。

<bean id="book" class="xxxx" autowire="byName"/>

<bean id="book" class="xxxx" autowire="byType"/>

其中byName,就是看beanid注入

  1. 开启自动注入

总结:其实自动装配可以看成是初步注入完bean之后二次注入bean.写配置的时候无先后之分。属于bean的管理


3.bean管理

1.属性值分离

1引入外部配置文件context:property-placeholder,需要先添加命名空间

2.${}取属性的值,

    <xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">
                                  
<context:property-placeholder location="classpath:jdbc.properties"/>
                                  

4.注解

为了简化xml的配置.

1.创建对象

  1. @Component
  2. @Service
  3. @Controller
  4. @Repositry

功能是一致的,只是为了方便开发.

步骤:

  1. 引入依赖
  2. 开启组件扫描,多个用逗号隔开
    • 在很多属性是数组,如果在xml配置中,使用分割在注解中使用{}加,分割
<context:component-scan base-package="com.example.bean,com.example.bean.Course"/>
包扫描写法
  1. 多个包用逗号隔开
  2. use-default-filters设置为false,可以自己设置扫描条件.,这里的扫描条件是根据注解的类型进行扫描
    • 关闭默认的过滤器,开启自己定义要扫描的类
    • 使用默认的过滤器,关闭相应的扫描类
  3. 排除的内容可以用默认扫描加上排除的内容
<context:component-scan base-package="com.autowire.bean" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

1.属性分析

  • value ~~id不写默认是类名

2.注入属性

1.bean注入

@Autowired

bean的注入,根据类型自动注入

不需要添加set方法帮我们封装了

@Qualifier

根据名称注入,需要个@Autowire的联合使用,存在多个相同类型的bean的时候,很适合根据名称注入

@Resource

单独使用,本身是javax里面的

  1. @Resource
  2. @Resource(name="userDao1")

混合方式注入。

@Service(value="userService")
public class UserService {

    @Autowired
    @Qualifier(value = "userDao1")
    private UserDao userDao;

    public void add(){
        userDao.add();
        System.out.println("service add..");
    }
}

2.普通属性注入@Value

3.纯注解开发@Configuration

需要完全替代配置文件,所以要创建配置类Config,开启包扫描.

@Configuration
@ComponentScan(basePackages = {"com.autowire"})
public class FullyDemo1 {
}
public class FullyAuto1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FullyDemo1.class);
        UserService service = context.getBean("userService", UserService.class);
        service.add();
    }
}

2AOP

  1. 面向切面编程,就是对方法进行增强,降低业务逻辑之间的耦合度。

image

​ 核心就是在不修改原始代码的方式添加新功能。

0.类加载器

​ 类加载器的作用是,将class文件读入,定义成一个class类。然后就可以通过newInstance获取到实例。它的基本的功能和xml配置类的读取类似。

​ 一个类要相同,则需要他们的全类名类加载器完全相同。

1.自定义类加载器

//该加载器可以加载与自己在同一路径下的Class文件
public class MyClassLoader extends ClassLoader{
	@Override
	public Class<?> loadClass(String name) throws ClassNotFoundException{
		try {  
			String fileName=name.substring(name.lastIndexOf(".")+1)+".class";
			InputStream is=getClass().getResourceAsStream(fileName);  
			if(is==null){
				//不在当前路径下的类,例如Object类(JavaBean的父类),采用委派模型加载
				return super.loadClass(name); 
			}else{
				//在当前路径下的类,例如JavaBean类,直接通过自己加载其Class文件
				byte[] b=new byte[is.available()];
				is.read(b);
				return defineClass(name,b,0,b.length);   
			}
 
		} catch (IOException e) { 
			throw new ClassNotFoundException();
		}
	}
}

1.概念与原理

过程:

  • 配置切面类(增强方法集合)
  • 配置切入点
  • aop植入

1.底层原理

  1. Aop使用的是动态代理的方式。

第一种 有接口的情况,使用JDK动态代理。

创建代理对象,代理能使用原本对象的所有方法,同时可以进行增强,接口实现类代理对象

image

第二种 无接口的情况 , 使用CGLIB动态代理。

代理对象实际是重写个子类的代理对象

image

2.jdk动态代理

做法就是通过Proxy.newProxyInstance()方法创建代理对象。

第一个参数,jdk动态代理器的类加载器,就是当前类的加载器。

第二个参数,接口数组,用来规定代理的方法

第三个参数 ,实际代理对象,用来写增强方法

image

public class Typical {
    public static void main(String[] args) {
//        代理方法的接口
        Class[] interfaces={UserDao.class};
        UserDao userDao = new UserDaoImp();
        UserDao instance = (UserDao) Proxy.newProxyInstance(Typical.class.getClassLoader(), interfaces, new UserProxy(userDao));//用代理对象类生成代理对象,
        instance.add(1,2);
    }
} 


class UserProxy implements InvocationHandler {//增强方法,参数是被代理的对象
    private Object object;

    UserProxy(Object userDao){
        object = userDao;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行方法前..");
        Object invoke = method.invoke(object, args);
        System.out.println(invoke);
        System.out.println("执行方法后..");
        return invoke;
    }
}

2.术语

  1. 连接点: 被增强的方法。

  2. 切入点实际被增强的方法

  3. 通知

    1. 增强的逻辑
    2. 通知类型
      • 前置通知,在方法前
      • 后置通知,在方法后
      • 环绕通知,
      • 异常通知,发生异常时的处理
      • 最终通知,所有结束的通知
  4. 切面

    是个动作,就是把通知应用到切点的过程

AspectJ

​ spring框架是基于Aspectj实现的AOP操作,它是个独立的AOP框架,只是联合起来一起使用。

基于AspecJ实现AOP:

  • 配置文件
  • 基于注解实现

所需依赖:

image

切入点表达式
  1. 语法结构
execution([权限修饰符][返回类型][类全路劲][方法名称][参数列表]);
返回类型可以不写;
execution(*com.example.bean.User.*(..))

image

基于注解的AspectJ

1.用注解生成bean

被代理对象和代理对象都需要先生成ben

2.配置开始代理模式Aop

开启动态代理,部分的功能是使得一些注解和标签可以被spring框架识别。

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.写代理类(增强方法的集合)

  1. 公共的切入点可以通过方法抽取。Pointcut()

@Before(value="com.AspectJ.proxy.UserProxy.pointCut()")同时切入点也可以写成一个专门的类,通过全类名调用。

package com.AspectJ.proxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Author coder
 * @Date 2021/10/21 13:29
 * @Description
 */
@Component
@Aspect
public class UserProxy {
	//连接点可以通过方法抽取
    @Pointcut(value="execution(* com.AspectJ.bean.User.*(..))")
    public void pointCut(){

    }

    @Before(value="pointCut()")
    public void before(){
        System.out.println("before...");
    }

    
    @Before(value="execution(* com.AspectJ.bean.User.*(..))")
    public void before(){
        System.out.println("before...");
    }

    @After(value="execution(* com.AspectJ.bean.User.*(..))")
    public void finaRes(){
        System.out.println("after...");
    }

    @AfterReturning(value="execution(* com.AspectJ.bean.User.*(..))")
    public void after(){
        System.out.println("afterReturning..");
    }

    @AfterThrowing(value="execution(* com.AspectJ.bean.User.*(..))")
    public void ocuurEror(){
        System.out.println("error occured..");
    }

    @Around(value="execution(* com.AspectJ.bean.User.*(..))")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前..");
        point.proceed();
        System.out.println("环绕后..");
    }
}

代理的方法分为5类,前置,后置,环绕,异常方法,最终方法。执行顺序:

  1. 环绕前..public void around(ProceedingJoinPoint point)

  2. before

  3. 方法

  4. 环绕后

  5. 后置

  6. 最终

一场方法会中断这一过程,其他过程可掠过,但最终过程不会省略.

  1. @Order当有多个方法对内容进行中增强的时候,可以设立增强类的优先级,

    相对于对一个方法进行增强之后的方法进一步增强,优先级越高,增强方法包裹在越外面.@Order(1)数值越小,优先级越高。

基于xml的代理配置

    <bean id="book" class="com.AspectJ.aopxml.Book"/>
    <bean id="proxy1" class="com.AspectJ.aopxml.ComProxy1"/>

    <aop:config>
<!--        配置公共的切点-->
        <aop:pointcut id="point1" expression="execution(* com.AspectJ.aopxml.Book.*(..)"/>
<!--        配置切面类,切面由增强方法和切点组成,需要先指定是那个增强类,切面就是增强方法的集合-->
        <aop:aspect ref="proxy1">
            <aop:before method="before" pointcut-ref="point1"/>
        </aop:aspect>
    </aop:config>

基于全注解配置

就是需要用注解开启包扫描AOP代理

  • 开启某一项功能的注解:@EnableAspectJAutoProxy(proxyTargetClass=true)

3.JDBC

1.所需的依赖
image

  • spring-jdbc
  • spring-orm(整合其他的框架用的)
  • spring-tx事务管理
  • mysql-connector-java
  • druid-1.1.9.jar连接池

2注册druid连接池

3.注册jbcTemplate模板

4.配置到dao,service

批量处理

  1. BatchQuery(sql,list); list是传递的参数值构成对象的集合

image

传递Object[]数组的集合.

4.事务的概念

1.事务的基本知识

​ 1. 事务是数据库操作的基本单元,逻辑上一组操作,要么成功,要么都失败。方法对数据库的操作具有一致性,原子性,隔离性,持久性

2. 事务的特性**ACID**
  	1. 原子性
  	2. 一致性,有增有减
  	3. 隔离性, 事务之间不会相互影响
  	4. 持久性,数据库修改之后持久的变化。

事务就是有些事要么一起做,要么都不做,做到一半出现异常需要进行回滚。

开启事务的方法:

  • 开启事务

  • 进行业务逻辑

  • 没有异常提交

  • 有异常进行回滚

    事务一般加载service层,Spring事务管理有两种

    • 编程式事务管理
    • 声明式事务管理
      • 基于注解
      • 基于xml配置文件
      • 底层是AOP操作。

2.事务管理器操作

1.配置事务管理器(基于注解)

  1. 配置事务管理器下,需要告诉使用的是哪个数据库连接池

  2. 开始事务管理,需要注入数据源

    xmlns:tx="http://www.springframework.org/schema/tx"
    
    http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd  
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    
  3. 对需要增强的方法(或者类)添加注解

2.事务注解中的常用参数

image

  1. propagation: 传播行为

    事务方法:使得表中的数据发生变化的操作,就是事务方案。

    多事务方法之间的调用有事务的方法调用没有事务的方法,没有事务的方法调用有事务的方法....

    事务传播有七种行为:

  • required: add里面有事务,调用其他方法会自动使用当前的事务。如果add没事务,则创建一个新的事务。
  • required_new: add调用update,不论add是否有事务,都会自己创建一个新事务,将原来的挂起。
  • PROPAGATION_REQUIRED
    Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行
  • PROPAGATION_REQUES_NEW
    该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
  • PROPAGATION_SUPPORT
    如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
  • PROPAGATION_NOT_SUPPORT
    该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
  • PROPAGATION_NEVER
    该传播机制不支持外层事务,即如果外层有事务就抛出异常
  • PROPAGATION_MANDATORY
    与NEVER相反,如果外层没有事务,则抛出异常
  • PROPAGATION_NESTED
    该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
  1. isolation: 事务的隔离级别

    正在使用的数据会被隔离

    多事务操作之间不会产生影响,我们称为事务的隔离性。不隔离会产生诸多的问题:脏读(一个事务读取到另一个正在运行的事务的数据),不可重复读(一个未提交的事务读取到另一个提交事务修改的数据未提交的事务每次读出的数据不一样),幻读(一个为提交的事务读到了另一个事务新增的记录);

    利用事务的隔离性,来解决这些问题

  • read uncommited(读未提交的)
  • read commited(读已提交的数据)
  • repeated read默认为可重复读
  1. timeout:超时时间

    事务在规定时间内提交。否则回滚,默认为-1,不操作。

  2. readOnly: 是否只读

    默认值为false,只可以查询到意思

  3. rollbackFor()回滚

    设置出现哪些异常进行回滚

  4. norollbackFor()

    出现哪些异常不进行回滚

3.基于xml配置事务

  1. 在spring中配置事务管理器
  2. 配置通知(增强的部分)tx-advice,如果是切面的话配置代理类和切面方法,事务则是配置通知。
  3. 配置切点和切面。

开始事务不需要了,因为不需要进行事务扫描,自己配置。

4.完全注解开发

  • 将事务bean取代,通过@Bean实现
    • @Bean指定的方法所需的参数默认自动通过已有的bean注入,核心根据类型注入.
  • 通过注解开启事务扫描。@EnableTransactionManagement
原文地址:https://www.cnblogs.com/hjw201983290498/p/15599628.html