Spring学习小结_2

这篇具有很好参考价值的文章主要介绍了Spring学习小结_2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


篇1

Spring学习小结_1
https://blog.csdn.net/m0_58730471/article/details/130075657?spm=1001.2014.3001.5501

12 Bean的生命周期

Spring Bean的生命周期是从 Bean 实例化之后(在内存中开辟空间),即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期(完整的说还要加上消亡)。

Spring Bean的生命周期大体上分为三个阶段:
Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的,是否是延迟加载的,是否是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;
Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。
Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。

Bean的初始化阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等、spring高频面试题Bean的循环引用问题都是在这个阶段体现的,所以重点阐述初始化阶段。

Bean的初始化阶段

Spring Bean的初始化过程涉及如下几个过程:
⚫ Bean实例的属性填充
⚫ Aware接口属性注入
⚫ BeanPostProcessor的before()方法回调
⚫ InitializingBean接口的初始化方法回调
⚫ 自定义初始化方法init回调
⚫ BeanPostProcessor的after()方法回调

Bean实例属性填充

Spring在进行属性注入时,会分为如下几种情况:
注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;

    <bean class="com.hyl.service.impl.UserServiceImpl" id="userService">
        <property name="name" value="hyl"/>
    </bean>

注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;

    <bean class="com.hyl.mapper.impl.UserDaoImpl" id="userDao"/>
    
    <bean class="com.hyl.service.impl.UserServiceImpl" id="userService">
        <property name="userDao" ref="userDao"/>
    </bean>

注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题

	<bean class="com.hyl.mapper.impl.UserDaoImpl" id="userDao">
        <property name="userService" ref="userService"/>
    </bean>
    
    <bean class="com.hyl.service.impl.UserServiceImpl" id="userService">
        <property name="userDao" ref="userDao"/>
    </bean>

循环引用

多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用"
Spring学习小结_2

    <bean class="com.hyl.service.impl.UserServiceImpl" id="userService">
        <property name="userDao" ref="userDao"/>
    </bean>

	<bean class="com.hyl.mapper.impl.UserDaoImpl" id="userDao">
        <property name="userService" ref="userService"/>
    </bean>

Spring学习小结_2

执行创建过程:
Spring学习小结_2

Spring提供了三级缓存存储 完整Bean实例半成品Bean实例 ,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
	Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
	
	//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
	Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
	
	//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
	Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

}

UserService和UserDao循环依赖的过程结合上述三级缓存描述一下
UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存;
UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
UserService 注入UserDao;
UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存。

图解:

按上述配置文件中的bean书写顺序,容器创建,先去实例化id=userService的bean(在内从中开辟空间),当前属于半成品bean,存入三级缓存中,之后进行属性的注入(需要注入id=userDao的bean),现在容器中还没有id=userDao的bean,所以暂定userService的后续创建,拐去创建userDao,同理也是先实例化userDao,当前也属于半成品bean,也存入三级缓存

//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

由源码可知放入三级缓存中的半成品bean外边是套了一层ObjectFactory的。

Spring学习小结_2

userDao在实例化存入三级缓存后,进行属性的注入。唉,发现,他需要注入userService,就先去一级缓存(单利池)中找,没有找到,再去二级缓存中找,还是没有,就去三级缓存中找,发现有需要的userService,就将其注入,并将三级缓存中的userService删除,在将userService存入二级缓存。

Spring学习小结_2

userDao在属性填充完后,继续执行后续的其他初始化流程,都执行完毕,称为一个完整的bean后,就从三级缓存中删除原来的userDao,将完整的userDao放入一级缓存(单利池)中。

Spring学习小结_2

之后userService结束暂停状态,从一级缓存中查找userDao,现在userDao已经存在了,就进行对应的属性注入,之后在执行完其他的初始化流程,得到一个完整的userService,就将二级缓存中的userService删除,将完整的userService也存入一级缓存(单利池)中。

Spring学习小结_2

Aware接口

Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象。

Aware接口 回调方法 作用
ServletContextAware setServletContext(ServletContext context) Spring框架回调方法注入ServletContext对象,web环境下才生效
BeanFactoryAware setBeanFactory(BeanFactory factory) Spring框架回调方法注入beanFactory对象
BeanNameAware setBeanName(String beanName) Spring框架回调方法注入当前Bean在容器中的beanName
ApplicationContextAware setApplicationContext(ApplicationContext applicationContext) Spring框架回调方法注入applicationContext对象

Spring IoC 整体流程总结

Spring学习小结_2

13 Spring整合MyBatis剖析

xml整合形式
导入坐标

		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
       <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

applicationConfig.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:db.properties"/>
    
    <!--创建userService对应的bean-->
    <bean class="com.hyl.service.impl.UserServiceImpl" id="userService" >
        <property name="userMapper" ref="userMapper"/>
    </bean>
    
	<!--配置数据源,使用el表达式,从db.properties中加载-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
    
    <!--创建SqlSessionFactory存入容器中-->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!--扫描指定路径下的mapper接口,自动创建对象,还是通过
    			this.getSqlSession().getMapper(this.mapperInterface)-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hyl.mapper"/>
    </bean>

</beans>

原理剖析
整合包里提供了一个SqlSessionFactoryBean和一个扫描Mapper的配置对象,SqlSessionFactoryBean一旦被实例化,就开始扫描Mapper并通过动态代理产生Mapper的实现类存储到Spring容器中。相关的有如下四个类:

  1. SqlSessionFactoryBean:需要进行配置,用于提供SqlSessionFactory;
  2. MapperScannerConfigurer:需要进行配置,用于扫描指定mapper注册BeanDefinition;
  3. MapperFactoryBean:Mapper的FactoryBean,获得指定Mapper时调用getObject方法;
  4. ClassPathMapperScanner:definition.setAutowireMode(2) 修改了自动注入状态,所以
    MapperFactoryBean中的setSqlSessionFactory会自动注入进去。

配置SqlSessionFactoryBean作用是向容器中提供SqlSessionFactory
SqlSessionFactoryBean实现了FactoryBean和InitializingBean两个接口,所以会自动执行getObject() 和afterPropertiesSet()方法

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
	...
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.dataSource, "Property 'dataSource' is required");
        Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
        Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
        this.sqlSessionFactory = this.buildSqlSessionFactory();
    }

    public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }
    ....
}

配置MapperScannerConfigurer作用是扫描Mapper,向容器中注册Mapper对应的MapperFactoryBean
MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor和InitializingBean两个接口,会在postProcessBeanDefinitionRegistry方法中向容器中注册MapperFactoryBean

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            this.processPropertyPlaceHolders();
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.set....
        ...
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
    }
}

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
		...
	    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
            this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
        } else {
            this.processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }
   ...
   private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
	   ....
		//设置Mapper的beanClass是org.mybatis.spring.mapper.MapperFactoryBean
		definition.setBeanClass(this.mapperFactoryBeanClass);
		.....
		//设置MapperBeanFactory 进行自动注入
		//autowireMode取值:1是根据名称自动装配,2是根据类型自动装配
		definition.setAutowireMode(2); 
	}
}
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
	public int scan(String... basePackages) {
	    ...
		this.doScan(basePackages);
		...
	}
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		...
		//将扫描到的类注册到beanDefinitionMap中,此时beanClass是当前类全限定名
		this.registerBeanDefinition(definitionHolder, this.registry);
		...
		return beanDefinitions;
	}
}
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
	public MapperFactoryBean(Class<T> mapperInterface) {
		this.mapperInterface = mapperInterface;
	}
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
	}
	public T getObject() throws Exception {
		return this.getSqlSession().getMapper(this.mapperInterface);
	}
}

14 Spring常用注解

Spring提供的注解有三个版本
2.0时代,Spring开始出现注解
2.5时代,Spring的Bean配置可以使用注解完成
3.0时代,Spring其他配置也可以使用注解完成,我们进入全注解时代

<bean> 标签及其标签属性的配置

<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" abstract="" autowire="" factory-bean="" factory-method=""></bean>
xml配置 注解 描述
<bean id=“” class=“”> @Component 被该注解标识的类,会在指定扫描范围内被Spring加载并实例化
<bean scope=“”> @Scope 在类上或使用了@Bean标注的方法上,标注Bean的作用范围,取值为singleton或prototype
<bean lazy-init=“”> @Lazy 在类上或使用了@Bean标注的方法上,标注Bean是否延迟加载,取值为true和false
<bean init-method=“”> @PostConstruct 在方法上使用,标注Bean的实例化后执行的方法
<bean destroy-method=“”> @PreDestroy 在方法上使用,标注Bean的销毁前执行方法

Bean依赖注入的注解

属性注入注解 描述
@Value 使用在字段或方法上,用于注入普通数据
@Autowired 使用在字段或方法上,用于根据类型(byType)注入引用数据
@Qualifier 使用在字段或方法上,结合@Autowired,根据名称注入
@Resource 使用在字段或方法上,根据类型或名称进行注入

@Autowired和@Resource的比较
共同点:

  1. @Resource注解和@Autowired注解都可以用作bean的注入.
  2. 在接口只有一个实现类的时候,两个注解可以互相替换,效果相同.

不同点:

  1. @Resource注解是Java自身的注解,@Autowired注解是Spring的注解.
  2. @Resource注解有两个重要的属性,分别是name和type。
    如果name属性有值,则使用byName的自动注入策略,将值作为需要注入bean的名字;
    如果type有值,则使用byType自动注入策略,将值作为需要注入bean的类型。
    如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。(即默认按照名称进行匹配,没有指定name属性,默认取字段名,按照名称查找,当找不到与名称匹配的bean时,才按照类型进行装配,按类型有多个时也报错)如果name属性一旦指定,就只会按照名称进行装配。
  3. @Autowired注解是spring的注解,此注解只根据type进行注入,不会去匹配name。但是如果只根据type无法辨别注入对象时,就需要配合使用@Qualifier注解或者@Primary注解使用。

@Qualifier配合@Autowired可以完成根据名称注入Bean实例,使用@Qualifier指定名称

@Autowired
@Qualifier("userDao2")
private UserDao userDao;

@Autowired
@Qualifier("userDao2")
public void setUserDao(UserDao userDao){
	System.out.println(userDao);
}

@Component衍生注解

为了每层Bean标识的注解语义化更加明确,@Component又衍生出如下三个注解

@Component衍生注解 描述
@Repository 在Dao层类上使用
@Service 在Service层类上使用
@Controller 在Web层类上使用

可以通过@Component注解的value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前类名首字母小写

非自定义Bean注解

非自定义Bean不能像自定义Bean一样使用@Component进行管理,非自定义Bean要通过工厂的方式进行实例化,使用@Bean标注方法即可,@Bean的属性为beanName,如不指定为当前工厂方法名称。工厂方法所在类必须要被Spring管理

如果@Bean工厂方法需要参数的话,则有如下几种注入方式:

  1. 使用@Autowired 根据类型自动进行Bean的匹配,@Autowired可以省略 ;
  2. 使用@Qualifier 根据名称进行Bean的匹配;
  3. 使用@Value 根据名称进行普通数据类型匹配。
//将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")
public DataSource dataSource(){
	DruidDataSource dataSource = new DruidDataSource();
	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
	dataSource.setUsername("root");
	dataSource.setPassword("root");
	return dataSource;
}

/****************************************************/

@Bean
@Autowired //根据类型匹配参数
public Object objectDemo01(UserDao userDao){
	System.out.println(userDao);
	return new Object();
}
@Bean
public Object objectDemo02(@Qualifier("userDao") UserDao userDao,
@Value("${jdbc.username}") String username){
	System.out.println(userDao);
	System.out.println(username);
	return new Object();
}

Bean配置类的注解

@Configuration注解标识的类为配置类,替代原有xml配置文件
该注解第一个作用是标识该类是一个配置类,第二个作用是具备@Component作用

@Configuration
public class ApplicationContextConfig {}

@ComponentScan 组件扫描配置,替代原有xml文件中的<context:component-scan base-package=“”/>
base-package的配置方式:
指定一个或多个包名:扫描指定包及其子包下使用注解的类
不配置包名:扫描当前@componentScan注解配置类所在包及其子包下的类

@Configuration
@ComponentScan({"com.xxx.service","com.xxx.dao"})
public class ApplicationContextConfig {}

@PropertySource 注解用于加载外部properties资源配置,替代原有xml中的<context:property-placeholder location=“”/> 配置

@Configuration
@ComponentScan
@PropertySource({"classpath:jdbc.properties","classpath:xxx.properties"})
public class ApplicationContextConfig {}

@Import 用于加载其他配置类,替代原有xml中的<import resource=“classpath:beans.xml”/>配置

如下一个基础的配置类(代替applicationContext.xml)

@Configuration
@ComponentScan({"com.xxx.service","com.xxx.dao"})
@PropertySource("classpath:jdbc.properties")
@Import(MybatisConfig.class)
public class ApplicationContextConfig {
}

其他注解

@Primary
@Primary注解用于标注相同类型的Bean优先被使用权,@Primary 是Spring3.0引入的,与@Component和@Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过@Autowired根据类型进行注入时,会选用优先级更高的。

@Repository("userDao")
public class UserDaoImpl implements UserDao{}

@Repository("userDao2")
@Primary
public class UserDaoImpl2 implements UserDao{}

@Profile
@Profile 注解的作用同于xml配置时学习profile属性<beans profile=“test”>,是进行环境切换使用的。
注解 @Profile 标注在类或方法上,标注当前产生的Bean从属于哪个环境,只有激活了当前环境,被标注的Bean才能被注册到Spring容器里,不指定环境的Bean,任何环境下都能注册到Spring容器里。

@Repository("userDao")
@Profile("test")
public class UserDaoImpl implements UserDao{}

@Repository("userDao2")
public class UserDaoImpl2 implements UserDao{}

指定被激活的环境de两种方式:
使用命令行动态参数,虚拟机参数位置加载 -Dspring.profiles.active=test
使用代码的方式设置环境变量 System.setProperty(“spring.profiles.active”,“test”);

注解整合mybatis

详细过程看这篇
https://blog.csdn.net/m0_58730471/article/details/128595925?spm=1001.2014.3001.5501
最主要的就是将下述的xml中的内容通过注解实现

<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Mapper包扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.dao"></property>
</bean>

使用@Bean将DataSource和SqlSessionFactoryBean存储到Spring容器中

@Bean
public DataSource dataSource(){
	DruidDataSource dataSource = new DruidDataSource();
	
	//dataSource.setXxx(); Xxx->driverClassName ,url ,username,password
	....
	
	return dataSource;
}

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
	SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
	sqlSessionFactoryBean.setDataSource(dataSource);
	return sqlSessionFactoryBean;
}

使用注解@MapperScan进行指明需要扫描的Mapper在哪个包下(代替MapperScannerConfigurer)

@Configuration
@ComponentScan("com.xxx")
@MapperScan("com.xxx.mapper")
public class ApplicationContextConfig {

}

注解方式,Spring整合MyBatis的原理,关键在于@MapperScan,@MapperScan不是Spring提供的注解,是MyBatis为了整合Spring,在整合包org.mybatis.spring.annotation中提供的注解。
源码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {
	String[] value() default {};
	String[] basePackages() default {};
	Class<?>[] basePackageClasses() default {};
	Class<? extends Annotation> annotationClass() default Annotation.class;
	// ... ...
}

重点关注一下@Import({MapperScannerRegistrar.class}),当@MapperScan被扫描加载时,会解析@Import注解,从而加载指定的类,此处就是加载了MapperScannerRegistrar。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,Spring会自动调用
registerBeanDefinitions方法,该方法中又注册MapperScannerConfigurer类,而MapperScannerConfigurer类作用是扫描Mapper,向容器中注册Mapper对应的MapperFactoryBean。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Spring与MyBatis注解方式整合有个重要的技术点就是@Import,第三方框架与Spring整合xml方式很多是凭借自定义标签完成的,而第三方框架与Spring整合注解方式很多是靠@Import注解完成的。

@Import可以导入如下三种类:
⚫ 普通的配置类
⚫ 实现ImportSelector接口的类
⚫ 实现ImportBeanDefinitionRegistrar接口的类

14 AOP

AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。

AOP相关概念

概念 单词 解释
目标对象 Target 被增强的方法所在的对象
代理对象 Proxy 对目标对象进行增强后的对象,客户端实际调用的对象
连接点 Joinpoint 目标对象中可以被增强的方法
切入点 Pointcut 目标对象中实际被增强的方法
通知\增强 Advice 增强部分的代码逻辑
切面 Aspect 增强和切入点的组合
织入 Weaving 将通知和切入点组合动态组合的过程

Spring学习小结_2

切点表达式

切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:

execution([访问修饰符]返回值类型 包名.类名.方法名(参数))

访问修饰符可以省略不写;
返回值类型、某一级包名、类名、方法名 可以使用 * 表示任意;
包名与类名之间使用单点 . 表示该包下的类,使用双点 .. 表示该包及其子包下的类;
参数列表可以使用两个点 .. 表示任意参数。

例子:

//表示访问修饰符为public、无返回值、在com.itheima.aop包下的TargetImpl类的无参方法show
execution(public void com.itheima.aop.TargetImpl.show())
//表述com.itheima.aop包下的TargetImpl类的任意方法
execution(* com.itheima.aop.TargetImpl.*(..))
//表示com.itheima.aop包下的任意类的任意方法
execution(* com.itheima.aop.*.*(..))
//表示com.itheima.aop包及其子包下的任意类的任意方法
execution(* com.itheima.aop..*.*(..))
//表示任意包中的任意类的任意方法
execution(* *..*.*(..))

AspectJ的五种通知类型:

通知名称 配置方式 执行时机
前置通知 < aop:before > 目标方法执行之前执行
后置通知 < aop:after-returning > 目标方法执行之后执行,目标方法异常时,不在执行
环绕通知 < aop:around > 目标方法执行前后执行,目标方法异常时,环绕后方法不在执行
异常通知 < aop:after-throwing > 目标方法抛出异常时执行
最终通知 < aop:after > 不管目标方法是否有异常,最终都会执行

xml配置的AOP

xml方式配置AOP的步骤:
1、导入AOP相关坐标;
2、准备目标类、准备增强类,并配置给Spring管理;
3、配置切点表达式(哪些方法被增强);
4、配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)。

导入AOP相关坐标

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

Spring-context坐标下已经包含spring-aop的包了,所以就不用额外导入了

Spring学习小结_2

使用aspect标签配置

准备目标类、准备增强类,并配置给Spring管理

Spring学习小结_2

配置切点表达式(哪些方法被增强)
配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)
切点表达式的配置方式有两种:

直接将切点表达式配置在通知上pointcut="";
也可以将切点表达式抽取到外面,在通知上进行引用pointcut-ref=""

<!--配置目标类,内部的方法是连接点-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
<!--配置通知类,内部的方法是增强方法-->
<bean id="myAdvice" class="com.itheima.advice.MyAdvice"/>

<!--将切点表达式抽取到外面,在通知上进行引用-->
<aop:config>
	<!--配置切点表达式,对哪些方法进行增强-->
	<aop:pointcut id="myPointcut" expression="execution(void com.itheima.service.impl.UserServiceImpl.show1())"/>
	<!--切面=切点+通知-->
	<aop:aspect ref="myAdvice">
		<!--指定前置通知方法是beforeAdvice-->
		<aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
		<!--指定后置通知方法是afterAdvice-->
		<aop:after-returning method="afterAdvice" pointcut-ref="myPointcut"/>
		...其他通知...
	</aop:aspect>
</aop:config>

<!--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->

<!--直接将切点表达式配置在通知上-->
<aop:config>
	<!--切面=切点+通知-->
	<aop:aspect ref="myAdvice">
		<!--指定前置通知方法是beforeAdvice-->
		<aop:before method="beforeAdvice" pointcut="execution(void com.itheima.service.impl.UserServiceImpl.show1())"/>
		<!--指定后置通知方法是afterAdvice-->
		<aop:after-returning method="afterAdvice" pointcut="execution(void com.itheima.service.impl.UserServiceImpl.show1())"/>
		...其他通知...
	</aop:aspect>
</aop:config>

环绕通知

public void around(ProceedingJoinPoint joinPoint) throws Throwable {
	//环绕前
	System.out.println("环绕前通知");
	//目标方法
	joinPoint.proceed();
	///环绕后
	System.out.println("环绕后通知");
}

<aop:around method="around" pointcut-ref="myPointcut"/>

异常通知
当目标方法抛出异常时,异常通知方法执行,且后置通知和环绕后通知不在执行

public void afterThrowing(){
	System.out.println("目标方法抛出异常了,后置通知和环绕后通知不在执行");
}

<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>

最终通知
类似异常捕获中的finally,不管目标方法有没有异常,最终都会执行的通知

public void after(){
	System.out.println("不管目标方法有无异常,我都会执行");
}

<aop:after method="after" pointcut-ref="myPointcut"/>

通知方法在被调用时,Spring可以为其传递一些必要的参数

参数类型 作用
JoinPoint 连接点对象,任何通知都可使用,可以获得当前目标对象、目标方法参数等信息
ProceedingJoinPoint JoinPoint子类对象,主要是在环绕通知中执行proceed(),进而执行目标方法
Throwable 异常对象,使用在异常通知中,需要在配置文件中指出异常对象名称

JoinPoint 对象,ProceedingJoinPoint对象,Throwable对象

//JoinPoint 对象
public void 通知方法名称(JoinPoint joinPoint){
	//获得目标方法的参数
	System.out.println(joinPoint.getArgs());
	//获得目标对象
	System.out.println(joinPoint.getTarget());
	//获得精确的切点表达式信息
	System.out.println(joinPoint.getStaticPart());
}


//ProceedingJoinPoint对象
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
	System.out.println(joinPoint.getArgs());//获得目标方法的参数
	System.out.println(joinPoint.getTarget());//获得目标对象
	System.out.println(joinPoint.getStaticPart());//获得精确的切点表达式信息
	Object result = joinPoint.proceed();//执行目标方法
	return result;//返回目标方法返回值
}


//Throwable对象
public void afterThrowing(JoinPoint joinPoint,Throwable th){
	//获得异常信息
	System.out.println("异常对象是:"+th+"异常信息是:"+th.getMessage());
}
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="th"/>

使用advisor标签配置

该方式需要通知类实现Advice的子功能接口

public interface Advice {
}

Advice的子功能接口
Spring学习小结_2
例如:
通知类实现了前置通知和后置通知接口 MethodBeforeAdvice, AfterReturningAdvice

public class Advices implements MethodBeforeAdvice, AfterReturningAdvice {
	//前置通知
	public void before(Method method, Object[] objects, Object o) throws Throwable {
		System.out.println("This is before Advice ...");
	}
	//后置通知
	public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
		System.out.println("This is afterReturn Advice ...");
	}
}

<aop:config>
	<!-- 将通知和切点进行结合 -->
	<aop:advisor advice-ref="advices" pointcut="execution(void com.itheima.aop.TargetImpl.show())"/>
</aop:config>

通知类实现了方法拦截器接口 MethodInterceptor(类似于环绕通知)

public class MyMethodInterceptor implements MethodInterceptor {
	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
		System.out.println("前置逻辑功能...");
		//执行目标方法
		Object invoke = methodInvocation.getMethod().invoke(methodInvocation.getThis(),methodInvocation.getArguments());
		System.out.println("后置逻辑功能...");
		return invoke;
	}
}

<aop:config>
	<!-- 将通知和切点进行结合 -->
	<aop:advisor advice-ref=“myMethodInterceptor" pointcut="execution(void com.itheima.aop.TargetImpl.show())"/>
</aop:config>

aspect和advisor配置区别

1、配置语法不同:

<!-- 使用advisor配置 -->
<aop:config>
	<!-- advice-ref:通知Bean的id -->
	<aop:advisor advice-ref="advices" pointcut="execution(void com.itheima.aop.TargetImpl.show())"/>
</aop:config>

<!-- 使用aspect配置 -->
<aop:config>
	<!-- ref:通知Bean的id -->
	<aop:aspect ref="advices">
	<aop:before method="before" pointcut="execution(void com.itheima.aop.TargetImpl.show())"/>
	</aop:aspect>
</aop:config>

2、通知类的定义要求不同
advisor 的通知类需要实现Advice的子功能接口;
aspect 不需要通知类实现任何接口,在配置的时候指定哪些方法属于哪种通知类型即可,更加灵活方便。
3、可配置的切面数量不同
一个advisor只能配置一个固定通知和一个切点表达式;
一个aspect可以配置多个通知和多个切点表达式任意组合,粒度更细。
4、使用场景不同
如果通知类型多、允许随意搭配情况下可以使用aspect进行配置;
如果通知类型单一、且通知类中通知方法一次性都会使用到的情况下可以使用advisor进行配置;
在通知类型已经固定,不用人为指定通知类型时,可以使用advisor进行配置,例如Spring事务控制的配置;

注解配置的AOP

xml配置AOP时,我们主要配置了三部分:目标类被Spring容器管理、通知类被Spring管理、通知与切点的织入(切面)
将目标类、通知类交由Spring管理

//目标类
@Component("target")
public class TargetImpl implements Target{
	public void show() {
		System.out.println("show Target running...");
	}
}

//通知类
@Component
public class AnnoAdvice {
	public void around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("环绕前通知...");
		joinPoint.proceed();
		System.out.println("环绕后通知...");
	}
}

配置aop
Spring学习小结_2

@Component
@Aspect //第一步
public class AnnoAdvice {
	@Around("execution(* com.itheima.aop.*.*(..))") //第二步
	public void around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("环绕前通知...");
		joinPoint.proceed();
		System.out.println("环绕后通知...");
	}
}

注解@Aspect、@Around需要被Spring解析,所以在Spring核心配置文件中需要配置aspectj的自动代理
xml配置文件

<aop:aspectj-autoproxy/>

配置类,加@EnableAspectJAutoProxy注解

@Configuration
@ComponentScan("com.itheima.aop")
@EnableAspectJAutoProxy //第三步
public class ApplicationContextConfig {
}

注解方式通知类型

//前置通知
@Before("execution(* com.itheima.aop.*.*(..))")
public void before(JoinPoint joinPoint){}
//后置通知
@AfterReturning("execution(* com.itheima.aop.*.*(..))")
public void AfterReturning(JoinPoint joinPoint){}
//环绕通知
@Around("execution(* com.itheima.aop.*.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {}
//异常通知
@AfterThrowing("execution(* com.itheima.aop.*.*(..))")
public void AfterThrowing(JoinPoint joinPoint){}
//最终通知
@After("execution(* com.itheima.aop.*.*(..))")
public void After(JoinPoint joinPoint){}

切点表达式的抽取
使用一个空方法,将切点表达式标注在空方法上,其他通知方法引用即可

@Component
@Aspect
public class AnnoAdvice {
	//切点表达式抽取
	@Pointcut("execution(* com.itheima.aop.*.*(..))")
	public void pointcut(){}
	//前置通知
	@Before("pointcut()")
	public void before(JoinPoint joinPoint){}
	//后置通知
	@AfterReturning("AnnoAdvice.pointcut()")
	public void AfterReturning(JoinPoint joinPoint){}
	// ......
}

@EnableAspectJAutoProxy源码,使用的也是@Import导入相关解析类

package org.springframework.context.annotation;

import ...

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}

AOP原理剖析
Spring学习小结_2

15 基于AOP的声明式事务控制

Spring的事务分为:编程式事务控制 和 声明式事务控制

事务控制方式 解释
编程式事务控制 Spring提供了事务控制的类和方法,使用编码的方式对业务代码进行事务控制,事务控制代码和业务操作代码耦合到了一起,开发中不使用
声明式事务控制 Spring将事务控制的代码封装,对外提供了Xml和注解配置方式,通过配置的方式完成事务的控制,可以达到事务控制与业务操作代码解耦合,开发中推荐使用

Spring事务编程相关的类主要有如下三个

事务控制相关类 解释
平台事务管理器 PlatformTransactionManager 是一个接口标准,实现类都具备事务提交、回滚和获得事务对象的功能,不同持久层框架可能会有不同实现方案
事务定义 TransactionDefinition 封装事务的隔离级别、传播行为、过期时间等属性信息
事务状态 TransactionStatus 存储当前事务的状态信息,如果事务是否提交、是否回滚、是否有回滚点等

平台事务管理器PlatformTransactionManager是Spring提供的封装事务具体操作的规范接口,封装了事务的提交和回滚方法。不同的持久层框架事务操作的方式有可能不同,所以不同的持久层框架有可能会有不同的平台事务管理器实现。
例如:
MyBatis作为持久层框架时,使用的平台事务管理器实现是DataSourceTransactionManager。
Hibernate作为持久层框架时,使用的平台事务管理器是HibernateTransactionManager。

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}

声明式事务控制
这里是Spring整合Mybatis就采用的这个DataSourceTransactionManager事务管理器。Mybatis内部采用的是JDBC的事务。所以说如果你持久层采用的是JDBC相关的技术,就可以采用这个事务管理器来管理你的事务。

xml形式

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>

Spring学习小结_2

<?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:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- 配置包扫描   -->
    <context:component-scan base-package="com.hyl"/>
<!-- 引入外部资源   -->
    <context:property-placeholder location="classpath:db.properties"/>
<!-- 配置数据源  -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
<!-- 配置SqlSessionFactory   -->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!-- 配置MapperScannerConfigurer   -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hyl.mapper"/>
    </bean>

    <!--Spring提供的事务通知-->
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--针对特定方法的事务属性设置,这里均为默认
                每个事务有很多特性,例如:隔离级别、只读状态、超时时间等
                <tx:method name="方法名称"
                    isolation="隔离级别"
                    propagation="传播行为"
                    read-only="只读状态"
                    timeout="超时时间"/>
             -->
            <tx:method name="transformMoney"/>
        </tx:attributes>
    </tx:advice>
    <!--平台事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <aop:config>
        <!--    配置织入    -->
        <aop:advisor advice-ref="myAdvice" pointcut="execution(* com.hyl.service.impl.*.*(..))"/>
    </aop:config>
</beans>

注意:
Spring学习小结_2

事务定义信息配置,每个事务有很多特性

<tx:attributes>
	<tx:method name="方法名称"
	isolation="隔离级别"
	propagation="传播行为"
	read-only="只读状态"
	timeout="超时时间"/>
</tx:attributes>

isolation属性:指定事务的隔离级别,事务并发存在三大问题:脏读、不可重复读、幻读/虚读。
可以通过设置事务的隔离级别来保证并发问题的出现,常用的是READ_COMMITTED 和 REPEATABLE_READ.

isolation属性 解释
DEFAULT 默认隔离级别,取决于当前数据库隔离级别,例如MySQL默认隔离级别是REPEATABLE_READ
READ_UNCOMMITTED A事务可以读取到B事务尚未提交的事务记录,不能解决任何并发问题,安全性最低,性能最高
READ_COMMITTED A事务只能读取到其他事务已经提交的记录,不能读取到未提交的记录。可以解决脏读问题,但是不能解决不可重复读和幻读
REPEATABLE_READ A事务多次从数据库读取某条记录结果一致,可以解决不可重复读,不可以解决幻读
SERIALIZABLE 串行化,可以解决任何并发问题,安全性最高,但是性能最低

read-only属性:设置当前的只读状态,如果是查询则设置为true,可以提高查询性能,如果是更新(增删改)操作则设置为false。

<!-- 一般查询相关的业务操作都会设置为只读模式 -->
<tx:method name="select*" read-only="true"/>
<tx:method name="find*" read-only="true"/>

timeout属性:设置事务执行的超时时间,单位是秒,如果超过该时间限制但事务还没有完成,则自动回滚事务,不在继续执行。默认值是-1,即没有超时时间限制。

<!-- 设置查询操作的超时时间是3秒 -->
<tx:method name="select*" read-only="true" timeout="3"/>

propagation属性:设置事务的传播行为,主要解决是A方法调用B方法时,事务的传播方式问题的,例如:使用单方的事务,还是A和B都使用自己的事务等。事务的传播行为有如下七种属性值可配置

事务传播行为 解释
REQUIRED(默认值) A调用B,B需要事务,如果A有事务B就加入A的事务中,如果A没有事务,B就自己创建一个事务
REQUIRED_NEW A调用B,B需要新事务,如果A有事务就挂起,B自己创建一个新的事务
SUPPORTS A调用B,B有无事务无所谓,A有事务就加入到A事务中,A无事务B就以非事务方式执行
NOT_SUPPORTS A调用B,B以无事务方式执行,A如有事务则挂起
NEVER A调用B,B以无事务方式执行,A如有事务则抛出异常
MANDATORY A调用B,B要加入A的事务中,如果A无事务就抛出异常
NESTED A调用B,B创建一个新事务,A有事务就作为嵌套事务存在,A没事务就以创建的新事务执行

需要区分的是切点表达式指定的方法与此处指定的方法的区别?
切点表达式,是过滤哪些方法可以进行事务增强;
事务属性信息的name,是指定哪个方法要进行哪些事务属性的配置。
Spring学习小结_2

方法名在配置时,也可以使用 * 进行模糊匹配

<tx:advice id="myAdvice" transaction-manager="transactionManager">
	<tx:attributes>
	<!--精确匹配transformMoney方法-->
	<tx:method name="transformMoney"/>
	<!--模糊匹配以Service结尾的方法-->
	<tx:method name="*Service"/>
	<!--模糊匹配以insert开头的方法-->
	<tx:method name="insert*"/>
	<!--模糊匹配以update开头的方法-->
	<tx:method name="update*"/>
	<!--模糊匹配任意方法,一般放到最后作为保底匹配-->
	<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

注解形式

将上述xml中的配置写入配置类

@Configuration
@ComponentScan({"com.hyl"})
@MapperScan({"com.hyl.mapper"})
@PropertySource({"classpath:db.properties"})
//开启事务
@EnableTransactionManagement
public class SpringConfig{

	@Value("${driverClassName}")
    private String driverClassName;
    @Value("${url}")
    private  String url;
    @Value("${username}")
    private String username;
    @Value("${password}")
    private String password;

	//    配置数据源

    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setPassword(password);
        dataSource.setUsername(username);
        return dataSource;
    }
    @Bean
    public SqlSessionFactoryBean sessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sessionFactoryBean=new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        return sessionFactoryBean;
    }

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

将@Transactional注解放到需要开启事务的类或方法上,在注解里面配置对应的事务属性
例:

@Service
public class AccountServiceImpl  implements AccountService {
    @Autowired
    private AccountMapper accountMapper;


    @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,readOnly = false,timeout = 5)
    public void transformMoney(String from, String to, Integer money) {
       accountMapper.reduceMoney(money,from);
       accountMapper.addMoney(money,to);
    }
}

更多详情看这篇第6节,AOP事务管理
https://blog.csdn.net/m0_58730471/article/details/127782322?spm=1001.2014.3001.5501文章来源地址https://www.toymoban.com/news/detail-426160.html

到了这里,关于Spring学习小结_2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 文件包含漏洞学习小结

    目录 一、介绍 二、常见文件包含函数 三、文件包含漏洞代码举例分析 四、文件包含漏洞利用方式 4.1 本地文件包含 1、读取敏感文件 2、文件包含可运行的php代码 ①包含图片码 ②包含日志文件 ③包含环境变量getshell ④临时文件包含 ⑤伪协议 4.2 远程文件包含 4.3 文件包含常

    2024年02月09日
    浏览(35)
  • 【BEV】学习笔记之BEV模型学习小结

    1、 前言 对于自动驾驶来说,单相机识别无法满足现有要求,也有过将多相机中的检测结果进行整合的工作,但这种操作显然不够“优雅”,于是更多的在Bird’s Eye View(BEV)视角下进行识别,如下图所示。 BEV的重点是如何高效的设计BEV特征,目前可以分为两种:自底向上和自顶

    2024年02月11日
    浏览(36)
  • 云存储技术与应用学习小结

    认识云存储 1.1存储发展历史 1.1.1云存储出现 云存储技术,孕育在云计算技术的发展历程之中。基于云计算技术的发展,以及宽带业务的大幅度提速,为云存储的普及和发展提供了良好的技术支持。2004年,互联网进入WEB2.0时代后,人们更加注重资源的分析和信息的交互,这种

    2024年02月10日
    浏览(32)
  • 机器学习小结之KNN算法

    ​ KNN (K-Nearest Neighbor)算法是一种最简单,也是一个很实用的机器学习的算法,在《 机器学习实战 》这本书中属于第一个介绍的算法。它属于基于实例的 有监督学习 算法,本身不需要进行训练,不会得到一个概括数据特征的 模型 ,只需要选择合适的参数 K 就可以进行应用。

    2024年02月06日
    浏览(75)
  • 1776_树莓派简介视频学习小结

    全部学习汇总: GitHub - GreyZhang/little_bits_of_raspberry_pi: my hacking trip about raspberry pi. 卖树莓派的时候赠送了部分视频资料,今天看了一段,主要是对树莓派进行一个简单的介绍的视频。挑我自己感兴趣的大致总结如下: 树莓派其实是一个小巧的计算机,或者叫做卡片电脑,大小

    2024年02月09日
    浏览(37)
  • Xilinx ZYNQ 7000学习笔记三(小结)

    ZYNQ 7000的启动模式由外部引脚决定的,5个模式引脚MIO[6:2]用于配置NAND flash、并行NOR flash、Serial NOR (Quad-SPI)、SD flash以及JTAG 一共5种启动模式。具体而言就是复位时,zynq-7000 SOC对下述引脚进行连续3个时钟周期采样。复位采样MIO[6:2]并将采样的模式值保存到系统级控制寄存器SL

    2024年02月09日
    浏览(45)
  • FPGA应用学习笔记-----复位电路(二)和小结

    不可复位触发器若和可复位触发器混合写的话,不可复位触发器是由可复位触发器馈电的。    不应该出现的复位,因为延时导致了冒险,异步复位存在静态冒险  附加素隐含项,利用数电方法,消除静态冒险    这样多时钟区域还是算异步的,每一时钟区域用一个复位同步

    2024年02月13日
    浏览(44)
  • Matplotlib绘图知识小结--Python数据分析学习

    一、Pyplot子库绘制2D图表 1、Matplotlib Pyplot Pyplot 是 Matplotlib 的子库,提供了和 MATLAB 类似的绘图 API。 Pyplot 是常用的绘图模块,能很方便让用户绘制 2D 图表。 Pyplot 包含一系列绘图函数的相关函数,每个函数会对当前的图像进行一些修改,例如:给图像加上标记,生新的图像,

    2024年02月12日
    浏览(46)
  • SCI一区论文阅读小结之深度学习在气象领域应用(未完待续)

    最近文献调研,发现一个研究相近的师兄最近发的几篇文章给的启发性很高,阅读文献的同时也对这几篇文章做个总结,以防自己忘记,也分享给大家。 首先,甩出这位大佬的RG: https://www.researchgate.net/profile/Xuan-Tong-3/research 最近的研究都是将深度学习应用到气象领域的,比如

    2024年02月21日
    浏览(36)
  • Spring实现HTTPS方式访问服务(单向认证)

    目录 前言 一、基本概念 二、创建keyStore、trustStore 三、服务端配置 四、客户端配置 总结 参考链接 本文通过Spring来配置https服务,后续会将相关的知识内容简单讲解一下,该文章主要是https单向认证,双向认证实现过程将在后续不久的另外一边文章涉及,感兴趣的小伙伴可以

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包