【精简】Spring笔记

跳转链接(学习路线)及前言(更新中)

后端
Java

MySql

jdbc

javaEE/javaSE

Tomcat

Servlet

[JSP]

Spring

SpringMVC

SpringBoot

SpringCloud

zookeeper、kafka、ActiveMQ、RabbitMQ、RocketMQ、Lucene

增强
设计模式、数据结构与算法、Docker、Linux

前端
html

css

javascript

javascriptDOM操作

JQuery

ajax

vue

react

安卓

嵌入式

快速入门

引入maven依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
    </dependencies>

创建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>

添加配置项

 <bean id="userDao" class="com.shuxin.dao.impl.UserDaoImpl"></bean>	

创建一个main方法

        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserDao userDao = (UserDao) app.getBean("userDao");
        userDao.save();

配置文件详解

bean范围配置,scope属性

取值说明
singleton默认的、单例的
prototype多例的
requestWEB项目中,Spring创建一个Bean的对象,将对象存入到request域中
sessionWEB项目中,Spring创建一个Bean的对象,将对象存入到session域中
global sessionWEB项目中,应该在Portlet环境,如果没有Portlet环境那么globalSession相当于session

销毁和初始化方法(生命周期)

在对应bean中创建init和destory方法,在xml配置这两个方法以用于初始化和销毁

    <bean id="userDao" class="com.shuxin.dao.impl.UserDaoImpl" init-method="init" destroy-method="destory"></bean>

ClassPathXmlApplicationContext类中有个方法,有个方法,registerShutdownHook()注册关闭钩子,关闭容器

如果大量配置这种方法会很麻烦,这里有一个简化的使用方法

public class UserService implements InitializingBean, DisposableBean {

  private   UserDao userDao;

    // ...
    
    @Override
    public void destroy() throws Exception {
        // ...
    }

    @Override
    public void afterPropertiesSet() throws Exception {
	   // ...	
    }
}

别名配置

<bean id="userDao" name="dao" class="com.shuxin.dao.impl.UserDaoImpl"></bean>

依赖注入(bean实例化)

实例化的三种方式

1、无参构造方法实例化

也就是默认的方法,上面使用的都是

2、静态工厂实例化(了解)

在这里,静态类,接口和静态工厂是等价的

需要一个工厂类,工厂类必须有静态方法,并且返回一个需要被实例化的类

public class StaticFactory {

    public static UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

配置文件写工厂类

<bean id="factory" class="com.shuxin.factory.StaticFactory"></bean>
<bean id="userDao" class="com.shuxin.factory.StaticFactory" factory-method="getUserDao"></bean>
<!-- 				那个类是工厂类?  						 那个方法是造对象的? -->

3、实例工厂实例化bean(了解)

这里的getUserDao非静态的,所以需要创建工厂的实例(对象),再使用该实例来调用造对象的方法,来获取到返回值。

public class StaticFactory {

    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
    <bean id="factory" class="com.shuxin.factory.StaticFactory"></bean>

    <bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
 		<!-- 用哪个bean造对象?				用哪个方法造对象? -->

4、Factory(是第三种方式的完善版 掌握)

public class FactoryBean implements org.springframework.beans.factory.FactoryBean<UserDao> {

//    代替第三种方法,固定创建对象的方法的名字
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
    
    //这是第三个方法,这里控制该对象是否为单例
        @Override
    public boolean isSingleton() {
//        这是单例的,false为多例的(非单例)
        return true;
    }
}
<!-- 这种方式配置bean,那么配置文件内就会变得简单 -->
<bean id="userDao" class="com.shuxin.factory.FactoryBean">
					  <!-- 这里填factory的名称 -->


将Dao层注入到Service层

setter方式

	<!-- application.xml -->

	<bean id="userDao" class="com.shuxin.dao.impl.UserDaoImpl">

    </bean>

    <bean id="userService" class="com.shuxin.service.UserService">
        <property name="userDaolll" ref="userDao"></property>
    </bean>
// UserDaoImpl.java
public class UserDaoImpl{
    public void fun(){
          System.out.println("这是UserDaoImpl内的fun方法");
    }
}

// UserService.java
public class UserService{
    private UserDao userDaolll;
    
    public void fun(){
        userDaolll.fun();
         System.out.println("这是UserService内的fun方法");
    }
    
    //需要注意设置set方法
        public void setUserDaolll(UserDao userDaolll) {
        this.userDaolll = userDaolll;
        }
}

构造器方式

public class UserService implements {

  private   UserDao userDao;

    public UserService(UserDao userDao111) {
        this.userDao = userDao111;
    }
 }
  <bean id="userDao" class="com.shuxin.dao.impl.UserDaoImpl">

    </bean>

    <bean id="userService" class="com.shuxin.service.UserService">
<!--        <property name="userDaolll" ref="userDao"></property>-->
        <constructor-arg name="userDao111" ref="userDao"></constructor-arg>
    </bean>

自动装配

按类型装配

    <bean id="userService" class="com.shuxin.service.UserService">
        <constructor-arg type="int" value="18"></constructor-arg>
        <constructor-arg type="java.lang.String" value="zhangsan"></constructor-arg>
    </bean>
public class UserService {

    private int age;
    private String name;

    public UserService(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

按参数位置装配

    <bean id="userService" class="com.shuxin.service.UserService">
        <constructor-arg index="0" value="18"></constructor-arg>
        <constructor-arg index="1" value="zhangsan"></constructor-arg>
    </bean>
public class UserService {

    private int age;
    private String name;

    public UserService(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

强制性依赖使用构造器的方式,setter方法有概率不执行,所以必须初始化的类使用构造器的方式,可选的依赖使用stter注入。

倡导使用构造器,第三方框架大部分使用构造器注入方式,有必要时,使用两种,根据实际情况。

自己开发模块使用setter注入,因为不常写构造器。

自动装配

1、按类型(常用)

2、按名称

3、按构造方法

4、不启用自动装配

1、

    <bean id="userDao" class="com.shuxin.dao.impl.UserDaoImpl" />

    <bean id="userService" class="com.shuxin.service.UserService" autowire="byType" />
public class UserService {

    UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

按类型匹配,该类型的bean必须唯一,并且可以不写被装配的id属性

 <bean class="com.shuxin.dao.impl.UserDaoImpl" />

2、

    <bean id="userDao" class="com.shuxin.dao.impl.UserDaoImpl" />

    <bean id="userService" class="com.shuxin.service.UserService" autowire="byName" />
public class UserService {

    UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

按照UserService类的成员变量userDao的名来匹配,(更准确的说是按照set方法后的这个名字匹配)

自动装配不能用于简单类型

自动装配的优先级低于setter注入和构造器注入

集合注入

   <bean name="listTest" class="com.shuxin.demo.ListTest">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>shuxinxin</value>
                <value>123</value>
                <value>hello</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>ssss</value>
                <value>ssss</value>
                <value>abc</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="1" value="avbc"></entry>
                <entry key="2" value="abc"></entry>
                <entry key="3" value="shuxin"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">China</prop>
                <prop key="country">beijing</prop>
                <prop key="country">nanjing</prop>
            </props>
        </property>
    </bean>
public class ListTest {

    private int[] array;

    private List<String> list;

    private Set<String> set;

    private Map<String,String>map;

    private Properties properties;


    public ListTest() {
    }



    public void setArray(int[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

使用spring加载properties文件

<?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/beans/spring-context.xsd
">
    
    
    
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
    <!-- system-properties-mode="NEVER"不加载系统属性   加载多个  推荐使用classpath:*.properties  使用第三方jar包的话,使用classpath*:*.properties(不仅从该工程读,还可以从依赖中读) -->
     <context:property-placeholder location="jdbc.properties,jdbc2.properties,*.properties,classpath:*.properties" system-properties-mode="NEVER"></context:property-placeholder>

    <bean class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/shuxin
jdbc.username=root
jdbc.password=root

容器

使用文件加载xml配置文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

        ApplicationContext  ctx = new FileSystemXmlApplicationContext("D:\\data\\tomcat\\mysbtis1\\springioc\\src\\main\\resources\\applicationContext.xml");

按类型获取bean

        UserService bean = ctx.getBean(UserService.class);
        bean.fun();

注解开发

<?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.shuxin.service"></context:component-scan>
</beans>
@Component("ComponentBean")
// 这里不指定名称的话,访问时使用类型来访问
public class ComponentBean {
     public void save(){
         System.out.println("ComponetBean");
     }
}

纯注解

        
// 调用
		ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService bean = ctx.getBean(UserService.class);
        bean.fun();
// 新建一个配置类


// 设定当前类为配置类
@Configuration

// 设定扫描路径  多个写法  @ComponentScan({"com.shuxin","com.xxx",...})
@ComponentScan("com.shuxin")
public class SpringConfig {


}

bean管理

作用范围

控制单例非单例

@Scope默认为单例

@Scope(“singleton”)单例

@Scope(“prototyoe”)非单例

生命周期

@Component
@Scope("prototype")
public class UserService {


    @PostConstruct
    public void init(){

    }
    @PreDestroy
    public void destory(){

    }
    
    public void fun(){
        System.out.println("sdfsdfsdf");
    }
}
// pom.xml 高于11版本的jdk使用这个依赖
<dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>

注解开发依赖注入

注解开发依赖注入(自动装配)

@Component
public class UserService {

    @Autowired
    private UserDao userDao;
    
    
    public void fun(){
        userDao.save();
    }
}


// 如果有多个实现可以为其命名
@Repository("userDao1")
@Component("userDao1")
// 使用这个注解指定转配的实现类
    @Qualifier("userDao1")

简单类型

@Value("xiadada")

private String name;

从外部properties取值

1、在配置类添加注解,引入配置文件

@PropertySource("classpath:value.properties")
name="xiadada"

2、使用时

  @Value("${name}")
    private String name;

第三方bean

//@Configuration
public class JdbcConfig {
    //    获得管理的bean对象
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://127.0.0.1:3306/java");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
}



@Configuration
//@ComponentScan("com.shuxin.config")
@Import(JdbcConfig.class)  // 支持数组
public class SpringConfig {


}

整合mybatis

MybatiesConfig。java
public class MybatiesConfig {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setTypeAliasesPackage("com.shuxin.pojo");
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.shuxin.dao");
        return mapperScannerConfigurer;
    }
}


SpringConfig。java
@Configuration
@ComponentScan("com.shuxin")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatiesConfig.class})
public class SpringConfig {
}

JdbcConfig。java
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}

整合junit

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
    </dependencies>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class TestSSS {

    @Autowired
    private BookService bookService;

    @Test
    public void testBookService(){
        bookService.fun();
    }

}

简单类型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

引用类型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AOP

入门案例

1、导入坐标

aop的包默认导入(spring包的依赖)

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.20</version>
        </dependency>

2、制作连接点方法

3、制作共性功能

4、定义切入点

5、绑定切入点与通知的关系(切面)

@Component
@Aspect
public class MyAop {
    @Pointcut("execution(void com.shuxin.service.TestWan.fun())")
    private void fun(){}


//    共性功能
    @Before("fun()")
    public void commonFun(){
        System.out.println(System.currentTimeMillis());
    }
}
@Configuration
@ComponentScan("com.shuxin")
@EnableAspectJAutoProxy
public class SpringConfig {
}

切入点表达式

execution(void com.shuxin.service.TestWan.fun())

动作关键字:描述切入点的行为动作,例如execution表示执行到指定切入点

访问修饰符:public,private等,可以省略

返回值

包名

类/接口名

方法名

参数

异常名:方法定义中抛出指定异常,可以省略


“ * ” 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

execution(public * com.shuxin.*.UserService.find* (*) )

匹配com.shuxin包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法


“ … ” 多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

execution(public User com..UserService.findById(..)

匹配com包下的任意包中的UserService类或接口中所有名称为findByld的方法


专用于匹配子类类型

execution(* *..*Service+.*(..))

注意:

所有代码按照标准规范开发,否则以下技巧全部失效

描述切入点通常描述接口,而不描述实现类

访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)

返回值类型对于增删改类使用精准类型,加速匹配,对于查询类使用“通配快速描述

包名书写尽量不使用 … 匹配,效率过低,常用做单个包描述匹配,或精准匹配

接口名/类名书写名称与模块相关的采用匹配,例如UserService书写成Service,绑定业务层接口名

方法名书写以动词进行精准匹配,名词采用*匹配,例如getByld书写成getBy*,selectAll书写成selectAll

参数规则较为复杂,根据业务方法灵活调整

通常不使用异常作为匹配规则

通知类型

前置通知

@Before("fun()")
    public void commonFun(){
        System.out.println(System.currentTimeMillis());
    }

后置通知

@After("fun()")

环绕通知(重点)

    @Around("fun()")
    public Object commonFun(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("在前执行");
        Object ret = pjp.proceed();
        System.out.println("在后执行");
        return ret;  //或者返回原来本该返回的返回值,这里是ret(proceed方法返回原来的值)
    }

对有返回值的方法,需要在下面将return写上(会将return覆盖掉,在proceed方法返回原来的值)

注意

环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知

通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行

对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Obiect类型

原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object

由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

返回后通知(了解)

设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法正常执行完毕后运行

 @AfterReturning("fun()")
    public void commonFun(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("不抛异常才会在末尾执行");
    }

抛出异常后通知(了解)

设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行

@AfterThrowing("fun()")
    public void commonFun(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("抛异常才会在末尾执行");
    }

获取数据

获取切入点参数

JoinPoint:适用于前置、后置、返回后、抛出异常后通知

ProceedJointPoint:适用于环绕通知

获取切入点方法返回值

返回后通知

环绕通知

获取切入点方法运行异常信息

抛出异常后通知

环绕通知

事务

在需要添加事务的方法上添加注解,注意最好放到接口上

@Transactional
    public void transfer(int out,int in,Double money);

在jdbcConfig配置类添加

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

在SpringConfig配置类添加注解

@EnableTransactionManagement
public class SpringConfig {
}

事务角色

事务管理员

发起事务方,在spring中通常指代业务层开启事务方法

事务协调员

加入事务方,在spring中通常指代数据层方法,也可以是业务层方法

事务属性

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值