Spring-IOC

spring模块

在这里插入图片描述
Test:Spring的单元测试模块
core container(核心容器IOC):
在这里插入图片描述
aop+aspect(面向切面变成模块):
在这里插入图片描述数据访问:spring数据库访问模块:
在这里插入图片描述

Web:Spring开发web应用的模块
在这里插入图片描述
spring运行还需要一个人重要的日志文件:
commons-logging

SpringIOC发展史:

以前我们使用对象需要自己new
Student student = new Student();
student.setXxx();
现在我们使用IOC

IOC(控制反转)也可以称之为DI(依赖注入)IOC是一种思想,DI是实现:
主动地new变为被动的从容器中接收
控制反转:将 创建对象、属性值 的方式 进行了翻转,从new、setXxx() 反转为了 从springIOC容器getBean()
依赖注入:将属性值 注入给了属性,将属性 注入给了bean,将bean注入给了ioc容器;

细节:
1.那么对象是什么时候创建好的呢?
容器中对象的创建在容器创建完成的时候就已经创建好了(默认为单例,如果为多例,则在getBean后才会创建)
2.多次getBean得到的是一个对象么?
同一个组件在ioc容器中是单实例的。
3.ioc容器在创建这个组件对象的时候,(property)会利用setter方法为javaBean的属性进行赋值
4.javaBean的属性名是由什么决定的?
getter/setter方法决定的,去掉set方法的set,再把前面的字母大写就是property中name的值

依赖注入3种方式:

1.set注入:通过setXxx()赋值

赋值,默认使用的是 set方法();
依赖注入底层是通过反射实现的。
property中的name要写的和setXxx中的一样才能实现反射
根据Bean的id从IOC容器中获取bean实例

<property name="name" value="zhangshan"></property>
<property name="age" value="12"></property>

Person person = (Person) ioc.getBean(“person01”);
此时是需要强转的
根据Bean的类型从IOC容器中获取bean实例
Person person = ioc.getBean(Person.class);
这个时候是不需要强转的,但是当IOC中有两个Person的bean实例的时候会报错
在编写bean时,value当property的子元素时他需要加“”,但是当value当标签时,他不需要加“”,而且还可以使用type指定具体是什么类型的,

2.构造器注入:通过构造方法赋值

<constructor-arg name="name" value="zhuzhu"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>

需要注意:如果 < constructor-arg>的顺序 与构造方法参数的顺序不一致,则需要通过type或者index或name指定。
无论是String还是Int/short/long,在赋值时都是 value=“值” ,
因此建议 此种情况 需要配合 name\type进行区分
3.p命名空间注入
引入p命名空间
xmlns:p=“http://www.springframework.org/schema/p”

<bean id="course" class="org.lanqiao.entity.Course" p:courseHour="300" p:courseName="hadoop" p:teacher-ref="teacher">

他也是使用的set方法进行的赋值
注意多个 p赋值的时候 要有空格。

复杂赋值

1.当Person中又有了car类,而且要对某一个值赋空的时候,null是在property中又有了一个单独的< null/>标签

<bean id="person03" class="com.Person">
        <property name="age" value="21"></property>
        <property name="name" >
            <null/>
        </property>
        <property name="car">
            <bean class="com.Car">
                <property name="name" value="兰博基尼"></property>
                <property name="price" value="111111"></property>
            </bean>
        </property>
    </bean>

注意点:内部bean的id值写和没写是一样的,都不能获取到
2.各类集合的set方法注入
list:

<list>
                <value>足球</value>
                <value>篮球</value>
                <value>排球</value>
</list>

set:

<set>
                <value>足球</value>
                <value>篮球</value>
                <value>排球</value>
</set>

map:

<map>
                <entry>
                    <key>
                        <value>football</value>
                    </key>
                    <value>足球</value>
                </entry>
                <entry>
                    <key>
                        <value>basketball</value>
                    </key>
                    <value>篮球</value>
                </entry>
                <entry>
                    <key>
                        <value>paiball</value>
                    </key>
                    <value>排球</value>
                </entry>
</map>

数组:

<array>
                <value>足球</value>
                <value>篮球</value>
                <value>排球</value>
</array>

props:

<props>
                <prop key="football">足球</prop>
                <prop key="basketball">篮球</prop>
                <prop key="paiball">排球</prop>
</props>

这里的value是property的属性
< property name=“courseName” value=“java”>< /property>
value也可以当做标签在这里插入图片描述
赋其他值用value,赋空值直接用标签< null/>
当我们想要写的map让其他bean调用,此时我们可以配置spring配置文件头部的xmlns添加util空间。
3.当个bean中的对象的值有些些相同时,可以在bean中进行parent进行“继承”(但实际上并不是继承,因为两个对象的类型都是一样的,只不过是赋值了一份而已),此时第二个bean中就继承了第一个的值,若想该哪个值再往下进行重新赋值即可。当然我们也可以吧一个bean专门设置为抽象bean(在bean标签中关键字abstract=“true”),专门供其他bean使用

Bean的作用域:

一般只用以下两种:singleton和prototype
singleton(不指定的话,默认为单例):容器在初始化时,就会创建对象(唯一的一个);以后再getBean时,不再产生新的bean。singleton也支持延迟加载(懒加载):可以使用 @Lazy 来进行设置,只有getBean时才会创建对象
prototype:容器在初始化时,不创建对象;只是在每次使用时(每次从容器获取对象时 ,context.getBean(Xxxx)),再创建对象;并且 每次getBean()都会创建一个新的对象。

工厂模式

FactoryBean(工厂Bean)
FactoryBean是一个接口,实现它并且重写他的方法
1.准备bean。实现类和重写方法
2.注册bean。注册到@Bean中
可以根据重写的方法来设置单例多例,而且工厂默认不管是单例还是多例,都会到getBean的时候才会创建对象,

工厂模式适用的一些场景(不仅限于以下场景):

  1. 对象的创建过程/实例化准备工作很复杂,需要初始化很多参数、查询数据库等。

2.类本身有好多子类,这些类的创建过程在业务中容易发生改变,或者对类的调用容易发生改变。

注意:需要通过&区分 获取的对象是哪一个 : 不加&,获取的是最内部真实的Apple;
如果加了&,获取的 是FacotryBean

引用外部属性文件

1.需要添加context名称空间
2.还要写加载内部类:

<context:property-placeholder location="classpath:database.properties"/>

数据库连接池作为单例是最好的,一个项目就一个连接池,连接池里面管理很多连接,连接是直接去连接池中拿,所以我们可以让spring帮我们创建连接池。
我们习惯于把数据库的连接配置放在properties文件中

自动装配(只适用于 ref类型 )

约定优于配置
自动装配:
<bean ... class="org.lanqiao.entity.Course"  autowire="byName|byType|constructor|no" >

byName本质是byId
byName: 自动寻找:其他bean的id值=该Course类的属性名(一般就用这个)
byType: 其他bean的类型(class) 是否与 该Course类的ref属性类型一致 (注意,此种方式 必须满足:当前Ioc容器中 只能有一个Bean满足条件 )
constructor: 其他bean的类型(class) 是否与 该Course类的构造方法参数 的类型一致;此种方式的本质就是byType
可以在头文件中 一次性将该ioc容器的所有bean 统一设置成自动装配:

<beans xmlns="http://www.springframework.org/schema/beans"
...
default-autowire="byName">

自动装配虽然可以减少代码量,但是会降低程序的可读性,使用时需要谨慎。

sqel表达式

可以在value中用#{}进行赋值
${}取的是配置文件中的值

使用注解IOC容器中存放bean

想要使用注解:
1.就要导入AOP的包,
2.在xml文件中加入扫描注解所在的包

  • 我们也可以对扫描的包就行一些排除在这里插入图片描述
    在这里插入图片描述
    上面的是排除哪些包,下面的是只扫描哪些包

使用注解的id默认为该类的首字母小写,或者在注解后面加括号,给id重新命名
注解的作用域范围:默认就是单例

自动注入

@Autowired自动注入
当在某个类中定义了属性(这个属性是自定义类型的)上写了@Autowired,想要生效,这个属性对应的类必须得在容器中(并不是必须得用bean,扫描进入容器的也算是在容器中)。
当容器中有 两个类都是该属性时(一个继承另一个),此时会按照加了这个@Autowired的属性的变量名和这两个类的id进行比较(这两个类的id默认为首字母小写),
若我们没有按照首字母小写的当做变量名的时候,这两个类最终都不会被匹配上去,所以我们可以用:
@Qualifier("")来指定一个名当做id,不让spring使用变量名作为id。这里其实也可以把要自动注入的那个类的注解加个自定义id,如@Service(“book”)
注意:当把该自定义的类注入到容器中时,该类的方法也会随之注入进去
@Autowired自动注入找不到时就会报错,此时我们可以设置
@Autowired(required=false)

@Resourse,java的标准,他比spring 少了@Autowired(required=false)这个功能
如果面试问到@Resourse和@Autowired的区别:Resourse的扩展性更强,如果换到其他的容器,Resourse还可以用,Autowired就不可以用了

当@autowired放到方法上面时:如果里面没有参数,spring容器会在类加载完后执行一次这个方法;
如果方法中有参数的话,还会从容器中自动注入这个方法的参数,然后执行一次这个方法。
@autowired(required = false)作用在方法上,当方法有参数时,如果IOC容器中有方法参数的对象,那么会自动注入并执行方法一次;如果IOC容器中没有方法的参数对象,那么这个方法不会被执行,不管这个方法上有多少个参数,只要有一个参数对象是IOC容器中没有的,这个方法便不会被执行。如果方法没有参数,那么会被执行一次。

使用注解向IOC容器中存放bean

1.我们需要创建一个配置类,在上面加上@Configuration,表示这个是配置类
2.然后在@ComponentScan(basePackages={""}),写我们要扫描的包

3.然后将

ApplicationContext ioc=new ClassPathXmlApplicationContext("application.xml");

换成

ApplicationContext ioc=new AnnotationConfigApplicationContext(配置类.class)

1.此类属于非三层组件的方法

存bean
@Configuration
public class MyCourse {
    @Bean//id默认是方法名,类型是方法的返回值类型
    public Course myaaCourse(){
        Course course=new Course("java",4);
        course.setTeacher(new Teacher("张三"));
        return course;
    }
}
取bean
public static void testCourse2(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MyCourse.class);//这里括号里放的是前面写的那个类的名字,也可以用String 类型的,这里暂时用的是反射
        //set,构造器用的是ClassPathXmlApplicationContext("applicationContext.xml")
         Course course=(Course)context.getBean("myaaCourse");
        System.out.println(course);
    }

注解形式 给IoC容器中存放Bean:
1.有@Configuration的注解(配置类)(上面的那种方式)
2.三层组件加入IOC容器: 给个各类加 注解 、 扫描器识别注解所在包
给三层组件 分别加注解(@Controller、@Service、@Repository -> @Component)将注解所在包 纳入ioc扫描器(ComponentScan)
2.纳入ioc扫描器的两种方式:
①xml配置文件 :

<context:component-scan base-package="com.yanqun"  >
</context:component-scan>

②注解扫描器:@Configuration记住要加上这一句
在@ComponentScan(value="")""中加要扫扫描的文件,
这里也可以给扫描器指定规则:
过滤类型:FilterType(ANNOTATION,ASSIGNABLE_TYPE,CUSTOM)
在@ComponentScan()中加入(排除 ) excludeFilters={},{}里写

{@ComponentScan.Filter(type=FilterType.ANNOTATION,value=Service.class)}

也可以includeFilters={},但是这里需要注意,有默认行为,需要在最后
可以通过useDefaultFilters = false禁止
FilterType.ASSIGNABLE_TYPE可以对具体的类进行制定规则
CUSTOM自定义:自己定义包含规则

回顾给IoC加入Bean的方法
注解 :全部在@Configuration配置中设置:
三层组件: 扫描器 + 三层注解
非三层组件: ① @Bean+返回值
②@import(忘完了)
③FactoryBean(工厂Bean)
@import使用:
①直接编写到@Import中,并且id值 是全类名
②自定义ImportSelector接口的实现类,通过selectimports方法实现(方法的返回值 就是要纳入IoC容器的Bean) 。 并且 告知程序 自己编写的实现类。 @Import({Orange.class,MyImportSelector.class})
③编写ImportBeanDefinitionRegistrar接口的实现类,重写方法
@Import({Orange.class,MyImportSelector.class,ImportBeanDefinitionRegistrar.class})

Bean的生命周期:
方法一:(其实算是两种)
先在Course.java中写
init (), destroy()方法
xml:
init-method=“init” destroy-method=“destroy”
注解:
@Bean(value=“myaaCourse”,initMethod = “init”,destroyMethod = “destroy”)
由此得出了IOC容器在初始化时,会自动创建对象(构造方法) ->init ->…->当容器关闭时 调用destroy…(这是单例。多例时,容器关闭不会销毁)
singleton 他默认的是当容器创建的时候就直接创建对象,所以对象的创建会比init先
注意:在注解@bean中每个属性之间有逗号,而xml文件中的bean没有逗号
方法二:
写一个类可以是属于三层的,也可以不是
上面加 @Component注解
给初始化方法加@PostConstruct、给销毁方法加@PreDestroy
记得写扫描器
如果要获取@Component注解中的bean(中的某个方法),那么该Bean的名字就是@Component(value=“xxx”)的value值(xxx写这个类的名字)
方法三:两个接口
接口:适用于三层组件(扫描器+三层组件)
InitializingBean初始化
DisposableBean 销毁

初始化:只需要 实现InitializingBean中的afterPropertiesSet()方法
销毁:实现DisposableBean 中的destroy()方法
方法四:(给容器中的所有Bean加初始化、销毁)一个接口
接口:适用于三层组件
接口BeanPostProcessor:拦截了所有中容器的Bean
它可以对其他bean进行拦截,进行修改信息等操作;

如果是注解形式 , 随便写一个方法 ,然后加上相应注解即可
如果是接口形式,必须 实现接口中规定的方法

依赖注入: 当写了@Autowired时,该类会往IOC容器中有没有该类型的(一定是自己创建的类型,而不是普通数据类型和String 类型),
如果将@Autowired写在类的前面,则他没有使用set方法
如果将@Autowired写在set方法前,则他使用set方法
@Autowired 根据类型匹配:
三层注入方式/@Bean+返回值
1.如果有多个类型相同的,匹配哪个?
报错。 /默认值@primary
2.能否根据名字匹配?
可以,结合 @Qualifier(“stuDao2”)使用。
3.如果有0个类型相同,默认报错;可以修改成不注入(null),@Autowired(required=false)
自动注入方式一: @Autowired (Spring) ,默认根据类型
自动注入方式二 @Resource(JSR250),默认根据名字 (如果 有名字,根据名字匹配;如果没有名字,先根据名字查找,如果没找到,再根据类型查找);也可以通过name或type属性 指定根据名字 或类型找。
自动注入方式三: @Inject(JSR330),额外引入javax.inject.jar,默认根据类型匹配
自动注入方式四:@Reference
@Reference是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,需要dubbo配置使用。

component和bean的区别

bean是方法级别的注解,一般使用在@Configuration中,也可以用在@Component注解的类里,添加的bean的id值为方法名,类型为方法的返回值,
@component和Controller,Service,Repositor作用也都一样,都是加在类上面的,此时会经过扫描加入到容器中
@Bean的用途则更加灵活
当我们引用第三方库中的类需要装配到Spring容器时,则只能通过@Bean来实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值