spring

1.什么是ioc控制反转 ?

传统代码 ,耦合度太高,调其他类的方法需要new对象,现在将创建对象(通过配置文件)管理都交给beanFactory 来管理,开发人员用的时候只需要直接拿就行了。

反转的时bean的创建权。

2. 什么是di依赖注入?

beanFactory工厂 对象和对象之间的引用,比如在表述层有个control类需要掉用业务层的impl类,原来是得在control类里面new impl类,但是由于两个对象control
和impl都由beanfactory工厂管理创建,所以beanfactory工厂在创建control类的时候就会把impl对象赋值给control的一个属性,这个过程叫注入。不注入对象注入普通参数也是。

通过set方法

 <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"> <!--控制反转-->
        <constructor-arg name="name" value="张三"></constructor-arg> <!--通过有参构造创建bean对象 默认是通过无参构造-->
 
        <property name="userDao" ref="userDao"></property>   <!--依赖注入-->
    </bean>

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

3.applicationContext 叫ioc容器

早期只有beanfactory工厂 bean对象都由他创建, 现在有他的子接口applicationContext 叫ioc容器 比他更强大。

beanfactory是懒加载 只有在getbean的时候(使用这个对象的时候) 才加载对象 。

applicationContext在读取xml配置文件(项目启动)的时候就已经加载了。

4.bean标签

1.id:

//唯一不重复 如果不写 那么id就是全限定类名 每次getBean的时候 其实都是通过 name获取的 只不过 自动把id 转换成name了
 

 2.class:

//要配置的生成对象的全限定类名


3.name:

//起一个别名 可以按,分开其多个名字name=“aaa,bbb,ccc”


4.scop:

//对象的作用范围,就是生成的对象放在什么位置。

1. singleton:

  //单例,不写默认就是这个,spring容器创建的时候就会生成,用完再放回去。  
 疑问? 项目部署的时候多线程访问一个项目 要用同一个 对象 那么在beanFactory共工厂里面还是只有一个吗?

回答:是,他们都用同一个实例对象,所以设计的时候要设计成无状态实例它们可以同时执行任务,不会相互阻塞。

 2.prototype:    

//多例,只有在getbean的时候才会创建对象,用完直接销毁。所以每次getBean的地址都不一样。
 拓展://如果导入了spring-webmvc 那么还会有两种 requet和session 和第一种一样 也只有一个 不过存的位置不一样


5.lazy-init:

//是否开启延迟加载 只对applicationContext有效 可以让他 getBean的时候在创建bean


6.init-method:

//指定初始化方法  创建对象后执行 对象中的 自定义方法

注意:实现initializingBean接口重写afterpropertiesSet()方法 会比init-method配置的方法还要早执行,

 基本执行顺序 创建对象=》给属性赋值=》afterpropertiesSet()=》init-method()》destory-method


7.destory-method:

//指定销毁方法 容器 关闭前执行


8.factory-method:

//工厂方式创建对象,此时不会调用构造而是,调用自定义的静态方法(这个方法 new 对象 然后return回来)创建对象, 

好处1:可以在创建之前做其他的操作,(毕竟方法是自己写的)。 

好处2:一些不是自己定义的bean如第三方jar包里面的bean也需要交给spring管理,就是通过这种方式。(springboot存疑?)

注意工厂模式 产生的实例对象是 方法return 的返回值

1.静态工厂

<!--静态工厂方法方式  由于工厂是静态的不需要实例化-->
<bean id="userDao1" class="com.itheima.factory.MyBeanFactory1" factory-method="userDao">
        <constructor-arg name="name" value="haohao"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
    </bean>
public class MyBeanFactory1 {
    public static UserDao userDao(String name,int age){
        //Bean创建之前可以进行一些其他业务逻辑操作
        return new UserDaoImpl();
    }
}

2.非静态工厂

<!--非静态工厂 需要先配置工厂 实例化工厂 -->
    <bean id="myBeanFactory2" class="com.itheima.factory.MyBeanFactory2"></bean>

    <bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao">
        <constructor-arg name="username" value="haohao"/>
    </bean>
public class MyBeanFactory2 {
    public UserDao userDao(String username){
        //Bean创建之前可以进行一些其他业务逻辑操作
        return new UserDaoImpl();
    }
}

3.通过fatcoryBean  spring提供的接口

这种方式举有延迟实例化对象功能,只有getBean(获取用到对象)的时候才会 实例化对象 并把对象 放在beanFactory的缓存中。

<bean id="userDao3" class="com.itheima.factory.MyBeanFactory3"></bean>
public class MyBeanFactory3 implements FactoryBean<UserDao> {

    @Override
    public UserDao getObject() throws Exception {
        System.out.println("getObject被调用...");
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

9.注入方式

10.自动装配 autowire 

 如果一个标签的id和另一个标签的name一样,Spring 会优先选择 name 匹配的 Bean。

11.xml文件 命名空间引用 


一个主配置文件 引入其他配置文件 使其生效

<import resource="classpath:UserModuleApplicationContext.xml"></import>

12.springbean实例化流程

spring容器在进行初始化时,会将xml配置的的信息封装成一个BeanDefinition对象,所有的 BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,使用反 射创建Bean实例对象,创建好的Bean对象存储在一个名为singletonObjects的Map集合中,当调用getBean方法 时则最终从该Map集合中取出Bean实例对象返回。 

⚫ 加载xml配置文件,解析获取配置中的每个的信息,封装成一个个的BeanDefinition对象;

⚫ 将BeanDefinition存储在一个名为beanDefinitionMap的Map中;

⚫ ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象;

⚫ 创建好的Bean实例对象,被存储到一个名为singletonObjects的Map中;

⚫ 当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回

13.spring后置处理器

1.BeanFactoryPostProcessor:‘ 

Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;只会执行一次

<bean class="com.itheima.processor.MyBeanFactoryPostProcessor"></bean>
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor的postProcessBeanFactory");
        //System.out.println("beanDefinitionMap填充完毕后回调该方法");
        
        //注册BeanDefinition  使用后置处理把自定义的bean 注册到map
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.itheima.dao.impl.PersonDaoImpl");
        //强转成DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        defaultListableBeanFactory.registerBeanDefinition("personDao",beanDefinition);
        
        
        //修改某个Beandifinition
        BeanDefinition beanDefinition2 = beanFactory.getBeanDefinition("userService");
        beanDefinition2.setBeanClassName("com.itheima.dao.impl.UserDaoImpl");
    }
}

1.自定义注解 装配bean 练习通过后置处理 和

@MyComponent("otherBean")
public class OtherBean {
}
public class MyComponentBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        //通过扫描工具去扫描指定包及其子包下的所有类,收集使用@Mycomponent的注解的类
        Map<String, Class> myComponentAnnotationMap = BaseClassScanUtils.scanMyComponentAnnotation("com.itheima");
        //遍历Map,组装BeanDefinition进行注册
        myComponentAnnotationMap.forEach((beanName,clazz)->{
            //获得beanClassName
            String beanClassName = clazz.getName();//com.itheima.beans.OtherBean
            //创建BeanDefinition
            BeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClassName(beanClassName);
            //注册
            beanDefinitionRegistry.registerBeanDefinition(beanName,beanDefinition);
        });

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

 

2.BeanPostProcessor:

Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。每实例化一个执行一次

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        /*if(bean instanceof UserDaoImpl){
            UserDaoImpl userDao = (UserDaoImpl) bean;
            userDao.setUsername("haohao");
        }*/
        System.out.println(beanName+":postProcessBeforeInitialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+":postProcessAfterInitialization");
            return bean;
    }
}

 1.在循环放入 signlObjects 前 给对象增强(动态代理 )

使执行这个对象的任何方法 前后都打印执行时间

public class TimeLogBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //使用动态代理对目标Bean进行增强,返回proxy对象,进而存储到单例池singletonObjects中
        Object beanProxy = Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    //1、输出开始时间
                    System.out.println("方法:" + method.getName() + "-开始时间:" + new Date());
                    //2、执行目标方法
                    Object result = method.invoke(bean, args);
                    //3、输出结束时间
                    System.out.println("方法:" + method.getName() + "-结束时间:" + new Date());

                    return result;
                }
        );

        return beanProxy;
    }
}

14.springBean 生命周期

2.springbean的初始化阶段

15.循环依赖问题

有A,B两个 对象,A中属性需要B注入,B中属性需要A注入,spring首先实例化A开辟内存空间,然后注入属性发现B还没有实例,就会先去实例化B,B需要注入A,怎么办?

当一个对象 需要注入另一个对象时,会先去一级缓存signltonObjects(最终单例池)里面去找,没找到会去,二级缓存earlySingletonObjects(被引用过的半成品bean)找,还没有就去三级缓存singletonFactories(实例化对象还没有注入属性的半成品bean)找。

16.常用的Aware接口

可以让一个普通bean 获取 到框架中的对象 比如 不是表述层的类 获取到 servletContext
 实现这个四个接口重写对应的方法 ,spring在生成对象时候 会自动执行这四个方法,就可以获取到 servletContext BeanFactory beanName ApplaicationContext 这四个对象,然后用属性接收一下就可以。

17.完整周期图

18.spring整合mybatis

不需要mybatis-config.xml文件了

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

    <!--配置数据源信息-->
    <bean id="dataSource" 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>

    <!--配置SqlSessionFactoryBean,作用将SqlSessionFactory存储到spring容器-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--MapperScannerConfigurer,作用扫描指定的包(dao层的接口还有对应的配置文件,放到beanfactory工厂),产生Mapper对象存储到Spring容器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.itheima.mapper"></property>
    </bean>

    <!--<bean class="com.itheima.processor.TimeLogBeanPostProcessor"></bean>-->

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

 19.spring注解开发

 <!--注解组件扫描:扫描指定的基本包及其子包下的类,识别使用@Component注解-->
    <context:component-scan base-package="com.itheima"/>

<context:property-placeholder location="classpath:jdbc.properties"/>
读取配置文件 放到spring容器

@Autowared会先根据类型匹配如果有多个会根据name在匹配

@Bean 注入 非自定义的对象(不能写在类上面)比如第三方框架的对象 想注入 spring容器 可以写在方法上

20.使用配置类替代配置文件

package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.itheima.anno.MyMapperScan;
import com.itheima.beans.OtherBean;
import com.itheima.imports.MyImportBeanDefinitionRegistrar;
import com.itheima.imports.MyImportSelector;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;

import javax.sql.DataSource;

@Configuration  //标注当前类是一个配置类(替代配置文件)+@Component
//<context:component-scan base-package="com.itheima"/>
@ComponentScan("com.itheima")//注解扫描使注解生效
//<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")//读取配置文件
//<import resource="xxx.xml"></import>
//@Import(OtherBean.class)//导入其他配置类
//@Import({MyImportSelector.class})
//@Import(MyImportBeanDefinitionRegistrar.class)
//Mapper的接口扫描
@MapperScan("com.itheima.mapper")//接口扫描实际上是为mapper(和xml文件)创建为对象放到spring容器中
@MyMapperScan
public class SpringConfig {

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

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

}
public class ApplicationContextTest {

    public static void main(String[] args) {

        //System.setProperty("spring.profiles.active","test");

        //xml方式的Spring容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //注解方式去加载Spring的核心配置类
        //ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        /*UserService userService = applicationContext.getBean(UserService.class);
        userService.show();*/
        /*Object userDao = applicationContext.getBean("userDao2");
        System.out.println(userDao);*/
        /*UserService userService = applicationContext.getBean(UserService.class);
        userService.show();*/
        OtherBean2 bean = applicationContext.getBean(OtherBean2.class);
        System.out.println(bean);


    }

@Profile

@Profile("test") //设置test环境的时候 才会注入到spring容器 
//没有注解的相当于任何环境都注入
public class UserDaoImpl implements UserDao {

    @Value("${jdbc.driver}")
    private String username;

    //@Value("lisi")
    public void setUsername(String username){
        this.username = username;
    }

    @Override
    public void show() {
        //System.out.println(username);
    }

21.自定义框架 


整合第三方框架 可以直接bean标签配置 ,第三方框架繁琐的的bean可以自定义命名空间,如果要整合注解 需要用import

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值