1. spring简介
Spring是一个分层的JavaSE/EE full-stack(一站式)轻量级开源框架。
2.spring的模块
3.Spring控制反转(IOC)
需求调用一个类中的方法,比如创建一个Helloworld类,调用Helloworld中的sayHello方法
3.1 传统的方式
首先创建一个HelloWorld类
public class HelloWorld {
private String name;
public void setName(String name)
{
this.name = name;
}
public void sayHello()
{
System.out.println("hello:"+name);
}
}
然后创建Main类测试
public class Main {
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.setName("tom");
helloWorld.sayHello();
}
}
分析:由于Main类需要调用Helloworld类中的sayHello方法,所以需要在Main方法中创建Helloworld类对象,然后改用该方法,如果Helloworld类中sayHello方法的参数改变,需要修改Helloworld类中的方法,而且需要修改Main类中调用的地方,类与类之间的耦合度过高。
Spring的方式
首先还是创建Helloworld类
public class HelloWorld {
private String name;
public void setName(String name)
{
this.name = name;
}
public void sayHello()
{
System.out.println("hello:"+name);
}
}
创建spring.xml配置文件
创建调用类Main
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("spring/springday1/Demo2/springdemo2.xml");
HelloWorld helloWorld = (HelloWorld) classPathXmlApplicationContext.getBean("helloWorld");
helloWorld.sayHello();
}
}
分析:spring方式通过spring容器(spring配置文件)将类交付给spring容器进行管理,当需要调用该类时,需要创建spring容器对象,通过该对象获取调用类。该种方式降低了类与类之间的耦合度,如果Helloworld的sayHello方法发生变化,不需要修改Main类,只修改Helloword中的方法即可。
有个问题需要注意:
如果Helloworld获中没有默认的构造方法,在实例化Helloworld对象时会报错。
总结:控制反转主要体现在调用类中的方方法时不再需要在调用类中实例化该类对象,通过Spring容器的对象获取类的实例,调用方法。举个简单的例子:A是厨师,B是材料,厨师需要使用材料,然后自己去拿材料,如果材料改变了,厨师要再去拿材料,厨师说不干了,太累了。于是C诞生了,C专门管理材料,厨师说我要小黄瓜,C把小黄瓜给了A,厨师说我要大黄瓜,C把大黄瓜给了A,厨师说我要大的扁的黄瓜,C把大的扁的黄瓜给了A。个人见解:spring容器相当于代理,为调用类管理被调用类的实例。
4. 依赖注入
(1)setter注入:如果注入的数据包含特殊字符使用]]>
(2)构造函数注入
]]>
bean="car"> bean ="car1">
5、Spring常用注解
5.1、组件注册
(1)@Configuration 标注在一个类中说明是配置类
(2)@Bean 配置类中一个方法,将该方法返回的对象注入Spring容器中,注入Spring容器中的id默认是方法名
获取容器中注入的Bean的名字可以通过
ApplicatonContext类中的getBeanNamesForType(类的类型)得到注入Bean的名称,getBeanDefinition()方法可以得到Spring容器中所有Bean的名称
(3)@ComponentScan通过包扫描中的方法将带有注解的类注入到Spring容器中,@ComponentScan支持重复注解
(3.1)@ComponentScans 可以写一组的@ComponentScan
(3.2)@ComponetScan与@Configuration类配合使用
(3.3)@Filter注解,按照指定的规则进行扫描过滤,规则主要包括:FilterType.ANNOTATION, FilteType.CUSTOME,FilterType.ASSIGNABLE_TYPE,FilterType.REGEX,其中FilterType.CUSTOME为自定义规则,自定义规则实现TypeFilter接口
(4)@Scope设置Bean的作用域:singleton 单例模式,prototype 原型模式,request同一次请求创建Bean,session同一个Session创建一个请求
(5)@Lazy 懒加载,是针对单实例Bean,这些单实例Bean在容器启动时就创建了,而使用该注解的Bean,在第一次获取Bean时创建Bean。
(6)@Conditional 按照条件给Spring中注入Bean,这个注解与@Bean配合使用,当满足@Conditional条件时,才允许该Bean注入Spring容器中
(6.1)获取环境变量使用:ConfigurableEnviroment 接口
(6.2)使用@Conditional必须实现Condition接口,编写Bean需要满足的条件
(7)@Import 给Spring容器中注入Bean,导入的id是全类名
(8)实现ImportSelector接口, 返回需要导入类的全类名数组,需要和@Import配合使用
(9)使用ImportBeanDefinition接口,无返回值类型,需要和@Import配置使用
(10)使用Spring中的FactoryBean接口,如果要获取FactoryBean的实现类,必须在实现类的id前加&符号
5.2、 Bean的生命周期
bean的创建----------------------------------------初始化--------------------------------------------------销毁过程
(1)指定Bean的初始化和销毁方法
(1.1)初始化方法的执行时机:对象创建完成,属性赋值结束。
(1.2)销毁方法的执行时机:单实例:在容器关闭时;多实例,Spring容器不会调用销毁方法。
(2)通过实现 InitializingBean,DisposableBean接口实现初始化和销毁方法
(3)使用JSR250标准 @PostConstruct,@PreDestroy
(4)使用BeanPostProcessor 接口:
populateBean(),属性赋值,属性赋值结束之后进行初始化
postProcessorBeforeInitialization(Object bean,String beanName):在初始化之前执行
invokeInitialMethod(),调用初始化方法
postProcessorAfterInitialization(Object bean,String beanName):在初始化之后执行
xxxxAware,拿到Spring的容器,使用不同容器的功能。
5.3、属性赋值
@Value 给属性赋值 :可以是数值、SPEL表达式,${}是从配置文件注入的值
使用${},需要导入外部文件,使用@PropertySource注解,该注解是重复的注解
5.4、自动注解
Spring使用依赖注入,完成对IOC容器中各个组件的依赖关系复制
(1)使用@Autowired注解,该注解可以标注在:方法,属性和方法参数上,默认按照类型去找类,如果找到多个使用属性名找到符合要求的Bean,
与其配合使用的@Qualifier使用指定名称获取Bean,@Primary默认使用首选的Bean
(2)@Resource,默认使用名称匹配Bean
(3)@Inject 与 @Autowired相似
(4)实现XXXAware,使用XXXProcessor处理,将Spring底层的组件传入实现Bean。
5.5、@Profile注解,可以根据不同环境,切换配置的功能,比如开发,测试、生产不同环境使用的数据源不同,此时可以使用@Profile使用不同的环境。