Spring

IOC

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.2</version>
</dependency>

加载bean

public class BeanFactory {

    private static Map container = new HashMap();


    static {
        //1:加载beans.xml配置文件
        InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");


        //2:解析xml文件(dom4j)
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputStream);

            Element beans = document.getRootElement();

            //获取根标签的子节点
            List<Element> elements = beans.elements();

            for (Element element : elements) {
                String idVal = element.attributeValue("id");

                String classVal = element.attributeValue("class");

                //实例化对象( //3:通过反射机制,去实例化对象)
                Class<?> clazz = Class.forName(classVal);

                Object obj = clazz.newInstance();


                //存放到map集合中
                container.put(idVal, obj);

            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static  <T extends Object> T getBean (String beanName,Class<T> beanType){


        Object obj = container.get(beanName);

        if (obj == null) {
            throw new RuntimeException("没有该对象");
        }

        return  (T)obj;

    }

DI

基本数据类型

<bean id="stu" class="com.qf.entity.Student">
    <!-- 依赖spring注入属性值  set方法注入
     stu.setName("张三")-->
    <!--    <property name="name" value="张三"/>-->
    <!--    <property name="age" value="18"/>-->
​
    <!-- 依赖spring注入属性值  通过构造方法注入-->
    <constructor-arg   value="张三" name="name"/>
    <constructor-arg  value="18" name="age"/>
​
</bean>

集合类型

<!-- 依赖注入list   -->
<property name="courses">
    <list>
        <value>java</value>
        <value>php</value>
    </list>
</property>
<!-- 依赖注入map   -->
<property name="data">
    <map>
        <entry key="a" value="avalue"></entry>
        <entry key="b" value="bvalue"></entry>
    </map>
</property>
<!-- 依赖注入set  -->
<property name="setData">
    <set>
        <value>1</value>
        <value>1</value>
        <value>1</value>
        <value>1</value>
        <value>2</value>
    </set>
</property>

引用类型

一个bean(spring管理) 依赖另外一个bean(spring管理)

1:外置的bean

<!--    配置orderservice-->
<!--<bean id="orderService" class="com.qf.service.OrderService">-->
<!--    &lt;!&ndash;  orderService.setOrderDao(orderDao1)  &ndash;&gt;-->
<!--    <property name="orderDao" ref="orderDao1"></property>-->
​
<!--</bean>-->
​
<!--&lt;!&ndash;配置orderDao&ndash;&gt;-->
<!--<bean id="orderDao1" class="com.qf.dao.OrderDao"></bean>-->

2:内置的bean

<bean id="orderService" class="com.qf.service.OrderService">
    <!--  orderService.setOrderDao(orderDao1)  -->
    <property name="orderDao" >
        <bean id="orderDao1" class="com.qf.dao.OrderDao"></bean>
    </property>
</bean>

Bean作用域

> spring默认的bean的作用域是单例的(singleton)
>
> 如果scope="singleton" ,当容器初始化的时候,立即完成这个bean的实例化
>
> ```
> <bean id="stu" class="com.qf.entity.Student" scope="singleton">
> ```

多例?
>
> 如果scope="prototype" ,当容器初始化的时候,这个bean不会立即实例化,在getBean的时候实例化
>
> ```
> <bean id="stu" class="com.qf.entity.Student" scope="prototype">
 

自动装配

bean

<?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 https://www.springframework.org/schema/context/spring-context.xsd">


<!--第一步:开启注解扫描功能-->
<context:annotation-config/>
<!--第二步:扫描包的方式去扫描组件-->
<context:component-scan base-package="com.qf"  />

<!--<bean id="orderService" class="com.qf.service.OrderService" autowire="byName" />-->
<!--<bean id="orderDao" class="com.qf.dao.OrderDao"></bean>-->
</beans>

注解

@Componet   组件,通用注解
@Service    service层的注解 
@Repository  持久层的注解
//@Configuration等价于beans.xml文件

ComponentScan等价于<context:component-scan base-package="com.qf.dao,com.qf.service"/>

PropertySource等价于<context:property-placeholder location="constant.properties"/>
@PropertySource("constant.properties")

//等价于<bean></bean>
    @Bean
    public Student getStudent(){
        Student student = new Student();
        student.setUsername("rose");
        return student;
    }

DI注解

@Autowired默认按类型装配(这个注解是属业spring的)【常用】
注意:根据类型自动注入,如果容器中该类型有多个,那么会抛异常

@Autowired,@Qualifier:通过这两个注解,可以指定name进行自动注入

@Resource(这个注解属于J2EE的)
1. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
2. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
3. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则为类型进行匹配,如果匹配则自动装配,如果多个则抛异常

@Value:主要是在组件中自动注入外部属性文件中的属性值
注意:必须在beans.xml中去加载外部属性文件

动态代理-jdk

> 前提:被代理对象必须实现接口
> Proxy.ProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

动态代理-cglib

> cgLib的动态代理  被代理对象不需要实现接口

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

SpringAOP

第一步:pom依赖

```xml
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.12.RELEASE</version>
</dependency>

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

配置

<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 配置被代理对象   -->
<bean id="orderService" class="com.qf.service.OrderService"></bean>
<!--配置advice-->
<bean id="myAdvice" class="com.qf.service.MyAdvice"></bean>


<!-- 配置aop-->
<aop:config>
        <!--   动作:将增强的逻辑加入到切入点(织入)  -->
        <aop:aspect ref="myAdvice">
            <aop:before method="before" pointcut="execution(public void com.qf.service.OrderService.saveOrder())"></aop:before>
        </aop:aspect>

</aop:config>


</beans>

完全注解

@Configuration
@ComponentScan(basePackages = {"com.qf"})
@EnableAspectJAutoProxy//开启aop注解开发

配置mybatis

配置sqlsessionfactorybean,会产 生一个sqlsessionfactory,这是个时候就需要加载mybatis核心配置文件mybatis-config。同时还需要mapperscanerconfigurer,将sqlsessionfactory交给他,同时需要把mapper包在哪告诉他,扫描后会进行代理实现将每一个接口实现,同时注入ioc容器


<context:annotation-config/>
<context:component-scan base-package="com.qf.service"/>

<!--    加载属性配置文件-->
<context:property-placeholder location="db.properties"/>
<!--    配置druid datasource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="${url}" />
    <property name="username" value="${username1}" />
    <property name="password" value="${password1}" />
</bean>

<!--    接管sqlsessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<!--    <property name="configLocation" value="mybatis-config.xml"/>-->
    <property name="dataSource" ref="dataSource"></property>

    <!--加载映射文件    -->
    <property name="mapperLocations" value="mappers/*.xml"></property>

    <!-- 配置插件   -->
    <property name="plugins">
        <array>
            <bean class="com.github.pagehelper.PageInterceptor"/>
        </array>
    </property>

    <!-- 别名扫描   -->
    <property name="typeAliasesPackage" value="com.qf.entity"/>

    <!-- 设置信息   -->
    <property name="configuration">
        <bean class="org.apache.ibatis.session.Configuration">
            <property name="mapUnderscoreToCamelCase" value="true"/>
        </bean>
    </property>

//编程式事务
    public void  save(){

        //开启事务
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        definition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);//设置隔离级别
        definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //设置事务的传播行为

        TransactionStatus status = manager.getTransaction(definition);

        try {
            //1:添加jack
            Student student = new Student("jack", "888", new Date());
            studentMapper.saveStudent(student);


            //2:添加rose

            Student student1 = new Student("rose", "999", new Date());
            studentMapper.saveStudent(student1);

            int i = 1/0;

            //提交事务
            manager.commit(status);

        } catch (Exception exception) {
            exception.printStackTrace();

            //回滚事务
            manager.rollback(status);
        }


    }

Spring如何管理事务?

  1. 编程事务处理:提供了transactiontemplate模板,利用改模板通过编程方式实现事务管理,缺点编写的麻烦,好处事务管理控制范围更为精准

    声明式事务处理:通过声明的方式,只需要在需要做事务增强的方法上利用transactional注解(启动事务功能),声明事务特征即可

Spring的事务传播方式有哪些?

事务传播类型说明
PROPAGATION_REQUIRED如果当前没有事务,则新建一个事务;如果已存在一个事务,则加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,则以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,则抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行操作,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

Spring的事务如何配置,常用注解有哪些?

对于声明式事务,是使用@Transactional进行标注的。这个注解可以标注在类或者方法上。

  • 当它标注在类上时,代表这个类所有公共(public)非静态的方法都将启用事务功能。

  • 当它标注在方法上时,代表这个方法将启用事务功能。

另外,在@Transactional注解上,我们可以使用isolation属性声明事务的隔离级别,使用propagation属性声明事务的传播机制。

Spring

FactoryBean:该接⼝以 bean 样式定义,但是它不是⼀种普通的 bean,它是个⼯⼚ bean,实现该 接⼝的类可以⾃⼰定义要创建的 bean 实例,只需要实现它的 getObject ⽅法即可。

说一说你对Spring容器的了解

Spring主要提供了两种类型的容器:BeanFactory和ApplicationContext。

  • BeanFactory:Spring 是基础类型的IoC容器,本质是个⼯⼚类,⽤于管理 bean 的⼯⼚,最 核⼼的功能是加载 bean,也就是 getBean ⽅法,通常我们不会直接使⽤该接⼝,⽽是使⽤其⼦接 ⼝。

  • ApplicationContext:包含 BeanFactory 的所有功能,还提供了其他⾼级的特性,⽐如:事件发布、国际化信息⽀持、统⼀ 资源加载策略等。正常情况下,我们都是使⽤的 ApplicationContext

2.4 说一说你对Spring IOC的理解

ioc原理

ioc 解决搞耦合,是通过di实现的,通过工厂模式利用反射并接卸xml文件,避免接口修改

加载xml配置文件,解析xml文件,拿到xml文档,拿beans根元素,获取根标签子节点(id,class)实例化对象 class。forname,存放2map集合,用工厂

说到IoC就不得不说DI(Dependency Injection),DI是依赖注入的意思,它是IoC实现的实现方式,就是说IoC是通过DI来实现的。由于IoC这个词汇比较抽象而DI却更直观,所以很多时候我们就用DI来代替它,

在具体的实现中,主要由三种注入方式:

  1. 构造方法注入

    就是被注入对象可以在它的构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。然后,IoC Service Provider会检查被注入的对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象。构造方法注入方式比较直观,对象被构造完成后,即进入就绪状态,可以马上使用。

  2. setter方法注入

    通过setter方法,可以更改相应的对象属性。所以,当前对象只要为其依赖对象所对应的属性添加setter方法,就可以通过setter方法将相应的依赖对象设置到被注入对象中。setter方法注入虽不像构造方法注入那样,让对象构造完成后即可使用,但相对来说更宽松一些, 可以在对象构造完成后再注入。

  3. 接口注入

    相对于前两种注入方式来说,接口注入没有那么简单明了。被注入对象如果想要IoC Service Provider为其注入依赖对象,就必须实现某个接口。这个接口提供一个方法,用来为其注入依赖对象。IoC Service Provider最终通过这些接口来了解应该为被注入对象注入什么依赖对象。相对于前两种依赖注入方式,接口注入比较死板和烦琐。

总体来说,构造方法注入和setter方法注入因为其侵入性较弱,且易于理解和使用,所以是现在使用最多的注入方式。而接口注入因为侵入性较强,近年来已经不流行了。

Spring是如何管理Bean的?

Spring通过IoC容器来管理Bean,我们可以通过XML配置或者注解配置,来指导IoC容器对Bean的管理。因为注解配置比XML配置方便很多,所以现在大多时候会使用注解配置的方式。

以下是管理Bean时常用的一些注解:

  1. @ComponentScan用于声明扫描策略,通过它的声明,容器就知道要扫描哪些包下带有声明的类,也可以知道哪些特定的类是被排除在外的。

  2. @Component、@Repository、@Service、@Controller

  3. @Autowired、@Qualifier。

2.6 介绍Bean的作用域

参考答案

默认情况下,Bean在Spring容器中是单例的,我们可以通过@Scope注解修改Bean的作用域。该注解有如下5个取值,它们代表了Bean的5种不同类型的作用域:

类型说明
singleton在Spring容器中仅存在一个实例,即Bean以单例的形式存在。
prototype每次调用getBean()时,都会执行new操作,返回一个新的实例。
request每次HTTP请求都会创建一个新的Bean。
session同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。
globalSession同一个全局的Session共享一个Bean,一般用于Portlet环境。

2.8 Spring是怎么解决循环依赖的?

参考答案

spring对循环依赖的处理有三种情况:

  1. 构造器的循环依赖:这种依赖spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常。

  2. 单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。

  3. 非单例循环依赖:无法处理。

接下来,我们具体看看spring是如何处理第二种循环依赖的。

Spring单例对象的初始化大略分为三步:

  1. createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象;

  2. populateBean:填充属性,这一步主要是多bean的依赖属性进行填充;

  3. initializeBean:调用spring xml中的init 方法。

使用了三级缓存。

这三级缓存的作用分别是:

  • singletonFactories : 进入实例化阶段的单例对象工厂的cache (三级缓存);

  • earlySingletonObjects :完成实例化但是尚未初始化的,提前暴光的单例对象的Cache (二级缓存);

  • singletonObjects:完成初始化的单例对象的cache(一级缓存)。

2.11 说一说你对Spring AOP的理解

参考答案

AOP(Aspect Oriented Programming)是面向切面编程,它是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。所谓切面,相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块。

AOP的术语:

  • 连接点(join point):对应的是具体被拦截的对象,因为Spring只能支持方法,所以被拦截的对象往往就是指特定的方法,AOP将通过动态代理技术把它织入对应的流程中。

  • 切点(point cut):有时候,我们的切面不单单应用于单个方法,也可能是多个类的不同方法,这时,可以通过正则式和指示器的规则去定义,从而适配连接点。切点就是提供这样一个功能的概念。

  • 通知(advice):就是按照约定的流程下的方法,分为前置通知、后置通知、环绕通知、事后返回通知和异常通知,它会根据约定织入流程中。

  • 目标对象(target):即被代理对象。

  • 引入(introduction):是指引入新的类和其方法,增强现有Bean的功能。

  • 织入(weaving):它是一个通过动态代理技术,为原有服务对象生成代理对象,然后将与切点定义匹配的连接点拦截,并按约定将各类通知织入约定流程的过程。

  • 切面(aspect):是一个可以定义切点、各类通知和引入的内容,SpringAOP将通过它的信息来增强Bean的功能或者将对应的方法织入流程。

Spring AOP:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值