0
点赞
收藏
分享

微信扫一扫

Spring学习小结_2

陆公子521 2023-04-30 阅读 108

文章目录


篇1

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

12 Bean的生命周期

Bean的初始化阶段

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>

循环引用

多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用"
在这里插入图片描述

    <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提供了三级缓存存储 完整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);

}

图解:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Aware接口

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

Aware接口回调方法作用
ServletContextAwaresetServletContext(ServletContext context)Spring框架回调方法注入ServletContext对象,web环境下才生效
BeanFactoryAwaresetBeanFactory(BeanFactory factory)Spring框架回调方法注入beanFactory对象
BeanNameAwaresetBeanName(String beanName)Spring框架回调方法注入当前Bean在容器中的beanName
ApplicationContextAwaresetApplicationContext(ApplicationContext applicationContext)Spring框架回调方法注入applicationContext对象

Spring IoC 整体流程总结

在这里插入图片描述

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作用是向容器中提供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常用注解

<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使用在字段或方法上,根据类型或名称进行注入

不同点:

@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层类上使用

非自定义Bean注解

//将方法返回值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
public class ApplicationContextConfig {}
@Configuration
@ComponentScan({"com.xxx.service","com.xxx.dao"})
public class ApplicationContextConfig {}
@Configuration
@ComponentScan
@PropertySource({"classpath:jdbc.properties","classpath:xxx.properties"})
public class ApplicationContextConfig {}

如下一个基础的配置类(代替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{}

注解整合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;
	// ... ...
}

14 AOP

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

在这里插入图片描述

例子:

//表示访问修饰符为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(* *..*.*(..))
通知名称配置方式执行时机
前置通知< aop:before >目标方法执行之前执行
后置通知< aop:after-returning >目标方法执行之后执行,目标方法异常时,不在执行
环绕通知< aop:around >目标方法执行前后执行,目标方法异常时,环绕后方法不在执行
异常通知< aop:after-throwing >目标方法抛出异常时执行
最终通知< aop:after >不管目标方法是否有异常,最终都会执行

xml配置的AOP

注解配置的AOP

举报

相关推荐

0 条评论