spring学习笔记

spring学习笔记

spring全家桶

  • spring,springmvc,spring boot,spring cloud
  • spring:出现在2002年,解决了企业开发的难度,减轻了项目模块之间的管理,类和类之间的管理,帮助开发人员创建对象,管理对象之间的关系,spring核心技术ioc,aop。能实现模块之间,类之间的解耦合

sping配置

  • 加入maven依赖

    <dependency>
    	<groupId>org.spingframework</groupId>
        <artifactId>sping-context</artifactId>
        <version>5.3.5.RELEASE</version>
    </dependency>
    
  • 主配置文件

    <!--这个xsd和mybatis的dtd一样,是一种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>
    

配置文件语法

<!--
	告诉spring创建对象
    声明bean,就是告诉spring要创建某个类的对象
    id:对象的自定义名称,唯一值,spring通过这个名称找到类
    class:类的全限定名,不能是接口,因为spring是通过反射机制创建对象必须是类
    class:类的全限定名,不能是接口,因为spring是通过反射机制创建对象必须是类

	spring就完成new这个对象的任务
	spring把创建好的对象放在map中,spring框架有一个map存放对象
	例如:springMap.put(id的值,对象)
	一个bean声明一个对象

	创建对象的时间就是在创建spring容器中,会创建配置文件中的所有对象
	spring默认调用的是类的无参构造方法
-->
<bean id="someService" class="com.liucheng.service.impl.SomeServiceImpl" />

<!--
	name:表示构造方法的形参名
	index:表示构造方法的参数的位置,从左到右0,1,2
	ref:构造方法的形参类型是引用型,使用ref
-->
<bean id="" class="">
	<constructor-arg name="" value="" />
    <constructor-arg name="" value="" />
</bean>
String config="beans.xml";
ApplicationContext context=new ClassPathXmlApplicationContext(config);
//通过id取得对象
Object object=context.getBean(String id);
//获取容器中对象的数量
int count=context.getBeanDefinitionCount();
//获取容器中每个定义的对象名称(id值)
String[] names=context.getBeanDefinitionNames();

di:依赖注入

di的实现两种方法

  • 在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
  • 使用spring中的注解,完成属性的赋值,叫做基于注解的id实现

di的语法分类

  • set注入(设置注入):spring调用类的set方法,在set方法可以实现属性的赋值。80左右都是使用的set注入
  • 构造注入,spring调用类的有参构造方法,创建对象,在构造方法中完成赋值

set注入

<!--必须要有set方法,set注入就是使用类的set方法赋值-->
<!--简单类型set赋值-->
<bean id="xx" class="[类全限定名]">
	<property name="属性名称" value="属性值" />
    <property name="属性名称" value="属性值" />
</bean>

<!--引用类型赋值-->
<bean id="xxx" class="[类全限定名]">
	<property name="属性名称" ref="[其他bean的id]" />
</bean>

构造注入

<!--必须要有有参构造方法-->
<!--一个construction-age标签表示构造方法的一个参数-->
<bean id="" class="">
	<constructor-arg name="[形参名]" value="[值]" />
    <constructor-arg name="" ref="[其他bean的id]" />
    <constructor-arg index="2" value="" />
</bean>

自动注入by name

当一个类引用类型属性的名称与对应类在配置文件的id相同就可以自动赋值

<bean id="xx" class="[类全限定名]" autowire="byName">
	<property name="属性名称" value="属性值" />
    <!--<property name="school" value="属性值" />-->
</bean>

<!--引用类型-->
<bean id="school" class="[类全限定名]">
	<property name="属性名称" value="" />
</bean>

自动注入by type

<bean id="xx" class="[类全限定名]" autowire="byType">
	<property name="属性名称" value="属性值" />
    <!--<property name="school" value="属性值" />   其中school类全限定名是com.liucheng.school-->
</bean>

<!--1.引用类型-->
<bean id="myschool" class="com.lilucheng.school">
	<property name="属性名称" ref="[其他bean的id]" />
</bean>

<!--2.引用类型的子类,可以成功赋值-->
<bean id="schoolSon" class="com.liucehng.primarySchool" >                        
</bean>


<!--3.接口与实现类,也可以成功赋值-->

<!--以上三类要保证符合条件的只有一个,有多个符合会报错-->

多配置文件

<!--主配置文件引用其他配置文件,不同文件间自动注入也是可以的+-->
<beans>
	<import resource="classpath:com.liucheng.spring-a.xml" />
	<import resource="classpath:com.liucheng.spring-b.xml" />
    
    <import resource="classpath:bao1,bao2" />
</beans>

引入资源文件

<context:property-placeholder location="classpath:url_zh_CN.properties" />

注解di注入

注解名
@Component
@Repository
@Service
@controller
@Value
@Autowired
@Resource

Component

Controller 控制器

Respository dao类

Service service类

Value(“xxx”)

Autowired

Resource

使用注解要求

<!--使用这个要在<beans>中声明组件(component)扫描器-->
<!--会扫描指定包及其子包中的所有类,找到类的注解,按照注解进行操作-->
<context:component-scan vase-package="[包名]" />


<!--还要加入新的约束文件-->
<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 
       https://www.springframework.org/schema/context/spring-context.xsd">
引入包的多种方式
<context:component-scan base-package="bao1" />
<context:component-scan base-package="bao2" />

<context:component-scan base-package="bao1;bao2" />

@Component

//不指定id名时,默认给的id名是类名首字母小写
@Component(value="myschool") or @Component("myschool") or @Component
public class Myshool{}
//相当于
<bean id="myschool" class="[类的全限定名]" />;

@Repository、@Service and @Controller

  • 作用与Component相似
  • @Repository是作用于持久层类上面:放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的。
  • @Service是最庸于业务层类上面的:放在service的实现类上面,表示创建service对象,可以有事务等功能的
  • @Controller是用于控制层类上面的:放在控制器的上面,表示创建控制器对象,能够接受用户提交的参数,显示请求的处理结果

@Value

//只能给基本类型和String类型赋值
@Value(value="3")
private int a;

@Value("3")
public void setA(int a){}

@Autowired

  • 用自动注入来给引用类型赋值
  • 默认是byType方式赋值
//byType
@Autowired
private School school;


//byName
@Autowired
@Qualifier(value="[id名]")
private School school;
  • 属性required
//默认是true,表示如果赋值失败,程序报错
@Autowired

//如果是假,不报错,程序继续执行
@Autowired(required=false)

@Resource

//默认byName,如果不行就是用byType
@Resource

//只使用byName
@Resource(name="[id名]")

spring用aspectJ框架实现aop(动态代理)

aop的术语

  • Aspect:切面,表示增强的功能,就是一堆代码,完成某一个功能。非业务功能,常见的切面功能有日志,事务,统计信息,参数检查,权限验证
  • JoinPoint:连接点,连接业务方法和切面的位置。
  • Pointcut:切入点,指多个连接点方法的集合
  • 目标对象:给哪个方法增加功能,这个类就是目标对象
  • Advice:通知,通知表示切面功能能执行的时间,实在业务方法的前面还是后面

maven依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.5</version>	
</dependency>

execution表达式

  • AspectJ定义了专门的表达式用于指定Pointcut
符号描述
*0至多个任意字符
方法参数中:表示任意多个参数;包名后:表示当前包及其子包
+类名后:表示当前类及其子类;接口后:表示当前接口及其实现类
//访问权限、包名与类名、抛出异常类型可以不写
execution(访问权限,方法返回值,包名.类名.方法名(方法参数),抛出异常类型);
//例子
//任意公共的方法
execution(public * *(..));
//任何一个以set开头的方法
execution(* set*(..));
//service包下的任意类任意返回值的任意方法
execution(* com.xyz.service.*.*(..));
//service包及其子包下的任意类任意返回值的任意方法
execution(* com.xyz.service..*.*(..));
//任意包的service子包下的任意类任意返回值的任意方法
execution(* *..service.*.*(..))

注解实现

  • 方法注解
注解名称描述
@Before在目标方法之前执行
@AfterReturning在目标方法之后执行,能获取目标方法的返回值,处理这个返回值
@Around
@AfterThrowing
@After
<!--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"
       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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
    <!--声明目标对象-->
    <bean id="student" class="com.liucheng.bean01.Student">
        <constructor-arg name="name" value="三国" />
        <constructor-arg index="1" value="2" />
    </bean>
    
    <!--声明切面类对象-->
    <bean id="myAspect" class="com.liucheng.MyAspect" />
    
    <!--
        声明自动代理生成器
        aspectj-autoproxy:会把spring容器中所有的目标对象,一次性生产代理对象
		所以要放在目标类和切面类的声明后面
    -->
    <aop:aspectj-autoproxy />
</beans>
注解详解
Before and After
/**
 * Aspect:是Aspectj框架中的注解
 *  作用:表示当前类是切面类
 *  切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
 *  位置:在类的上面
 */
@Aspect
public class MyAspect {
    /**
     * 定义方法:方法是实现切面功能
     * 方法的定义要求:
     * 1.公共方法 public
     * 2.方法没有返回值
     * 3.方法名称可以自定义
     * 4.方法可以有参数,也可以没有参数
     *  如果有参数,参数也不是自定义的,有几个参数可以用
     * 		1. JoinPoint jp
     */
    //例如:@Before(value="execution(public void com.liucheng.bean01.Student.doSome(String,Integer))")
    @Before(value="通过execution表达式得到的业务方法")
    public void myAspect(){}
}

//After比AfterReturning还要靠后,一般用于资源清除
//总是会执行,就算目标函数有异常也会执行
//相当于try cache里的finally
@AfterReturning
@AfterReturning(value="execution()" returning="[返回值名]")
public void myAfterReturning(Object [返回值名]){}
@Around
/**
 * 环绕通知方法的定义格式
 *  1.public
 *  2.必须有返回值,推荐Object
 *  3.方法有参数,固定的参数ProceedingJoinPoint
 *  Around:环绕通知
 *  属性:value 切入点表达式
 *  特点:
 *  1. 他是功能最强的通知
 *  2. 在目标方法的前面和后面都能曾强
 *  3.控制目标方法是否被调用
 *  4.修改原来目标方法的返回值,影响最后的调用结果
 *
 *  环绕通知,等同于jdk动态代理的InvocationHandler接口
 *  参数:ProceedingJoinPoint等同于Method,用来执行目标方法的
 *  返回值:就是目标指向的执行结果,可以被修改
 */
@Around(value = "execution(public * com.liucheng.bean01.Student.doAround())")
public Object MyAround(ProceedingJoinPoint pjp) throws Throwable {
    Object result=null;
    //可以把pjp(ProceedingJoinPrint extends JoinPoint)当做JoinPoint执行各种方法
    Object[] args = pjp.getArgs();
    //目标方法调用
    result=pjp.proceed();
    //加入功能
    result=(int)result+3;
    //返回修改后的结果
    return result;
}
参数详解
JoinPoint
//多个参数时,JoinPoint必须位于参数列表的第一个
public void myAspect(JoinPoint jp){
    jp.getSignature();	//获得方法的签名(定义)
    //void com.liucheng.bean01.Student.doSome(String,int)
    
    String jp.getSignature().getName();
    //doSame()
    
    Object[] jp.getArgs();
    //获得调用doSome方法使用的参数数组
}
Object [返回值名]
public void myAspect(Object ret){
    //ret传入的是引用地址,修改基础类型和String并不会改变
    //如果是引用型数据,改变值内属性就会改变返回值
}
execution表达式别名
//使用@PointCut来给表达式取别名
@PointCut(value="execution()")
public void myName(){}

@Before(value="myName()")
public void myAspect(){
    
}

动态代理的方式

  • spring在默认情况下,有接口实现的类的aop动态代理使用的是jdk动态代理
  • 没有接口实现的类使用的是cglib代理,cglib代理要求类能够继承
  • 如果没有接口实现也想要使用cglib代理
<aop:aspectj-autoproxy proxy-target-class="true" />

spring实现mybatis

mybatis相关

<!--在大项目中mybatis提供的连接池POOLED并不是很好,我们平时不会用这种方式-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/liucheng?useUnicode=true;characterEncoding=utf8;serverTimezone=GMT"/>
    <property name="username" value="root"/>
    <property name="password" value="1727894442"/>
</dataSource>

我们使用独立的连接池类替换mybatis默认的,把连接池类交给spring创建

  • 我们让spring创建以下对象

    1. 独立的连接池类对象,使用阿里的druid连接池
    2. SqlSessionFactory对象
    3. 创建dao对象
  • 需要学习的就是上面三个对象的创建语法,使用xml的bean标签

总体过程

  1. maven依赖
    1. spring依赖
    2. mybatis依赖
    3. mysql驱动依赖
    4. spring的事务的依赖
    5. mybatis和spring集成依赖,mybatis官方提供的,用来在spring项目中创建mybatis的SqlSessionFatory,dao对象
  2. 创建实体类
  3. 创建dao接口和mapper文件
  4. 创建mybatis主配置文件
  5. 创建service接口和实体类,属性是dao
  6. 创建spring的配置文件:声明mybatis的对象交给spring创建
    1. 数据源
    2. SqlSessionFactory对象
    3. dao对象
    4. 声明自定义的service
  7. 创建测试类,获取Service对象,通过service调用dao完成数据库的访问
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.5</version>
</dependency>



<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
        </includes>
        <filtering>false</filtering>
    </resource>
</resources>

配置文件

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="url" value="jdbc:mysql://localhost:3306/liucheng?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT" />
        <property name="username" value="root" />
        <property name="password" value="1727894442" />
        <property name="maxActive" value="20" />
</bean>
<!--创建SqlSessionFactory对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--set注入,把数据库连接池交付给dataSource属性-->
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
<!--
        创建dao对象,使用了SqlSession对象,使用getMapper(dao.class)方法
        MapperScannerConfigurer:在内部调用getMapper()生成每个dao接口的代理对象
    -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--把SqlSessionFactory对象的id给他创建SqlSession对象-->
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    <!--把dao接口的包名给他,每个接口都执行一次getMapper()方法,获得每个接口的代理对象
            创建好的dao对象放入到spring的容器中,id是类名首字母小写
        -->
    <property name="basePackage" value="com.liucheng.Dao" />
</bean>
public void test01(){
    String config="applicationContext.xml";
    ApplicationContext context=new ClassPathXmlApplicationContext(config);
    String[] names = context.getBeanDefinitionNames();
    StudentDao dao = (StudentDao) context.getBean("studentDao");
    List<Student> students = dao.selectStudents();
    students.forEach(System.out::println);
}

事务处理注解

@Transactional

  • 通过此注解将事务织入到相应的public方法之中,实现事务管理
属性默认值描述
propagationPropagation.REQUIRED用于设置事务传播属性,值类型为Propagation枚举
isolationIsolation.DEFAULT用于设置事务的隔离级别,值类型为Isolation枚举
readOnlyfalse用于设置该方法对数据库操作是否是只读(只查询)
timeout-1(没有时限)设置本操作与数据库连接的超时时限,单位秒,类型int
rollbackFor空数组指定需要回滚的异常类,类型为Class[](只有一个可以不使用数组)
rollbackForClassName空数组同上,不过类型为String[]
noRollbackFor空数组指定不需要回滚的异常类,类型为Class[](只有一个可以不使用数组)
noRollbackForClassName空数组同上,不过类型为String[]

步骤

中小型项目
<!--声明事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--连接的数据库,指定数据源-->
    <property name="dataSource" ref="dataSource" />
</bean>
<!--开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象-->
<tx:annotation-driven transaction-manager="transactionManager" />
/**
* 出现异常时
*	1.spring框架会首先检查方法抛出的异常是不是在rollbackFor的属性值中,在,就不管什么类型异常,一定rollback
*	2.若不在rollbackFor属性值中,判断是否是RunTimeException,是就rollback,不是就不。
*/
@Transactional(
    propagation = Propagation.REQUIRED,
    isolation = Isolation.DEFAULT,
    readOnly = false,
    rollbackFor = {
    	NullPointerException.class,RuntimeException.class
 	}
)

内部机制就是使用了@Around环绕通知

try{
    要进行事务的方法();
    spring事务管理.commit();
}cache(){
    spring事务管理.rollback();
}
大型项目
<!--加入spring-aspects依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.5</version>
</dependency>
<!--声明事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--连接的数据库,指定数据源-->
    <property name="dataSource" ref="dataSource" />
</bean>


<!--声明业务方法他的事务属性(隔离级别,传播行为,超时时间)
    id:自定义名称,表示标签间的配置内容
	transaction-manager:事务管理器对象的id
-->
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager" >
    <!--配置事务属性-->
    <tx:attributes>
        <!--给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
            name:方法名称,1)完整的方法名称,不带有包和类
                         2)方法可以使用通配符,*表示任意字符
       	-->
        <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"/>
        <tx:method name="b*" propagation="REQUIRED" isolation="DEFAULT" />
    </tx:attributes>
</tx:advice>


<aop:config>
    <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
    <!--配置增强器:关联advice和pointcut-->
    <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="servicePt" />
</aop:config>

Web项目获得ApplicationContext对象

  • 使用spring给我们的Context监听器
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  • 把.xml配置文件路径给spring
<context-param>
	<param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
  • java文件获得ServletContext里的ApplicationContext对象
WebApplicationContext context=null;
context=WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值