Spring是一个轻量级的IOC(控制反转)/DI(依赖注入)和AOP(面向切面编程)框架,Spring作者认为
业务中用到的对象【创建、初始化、销毁】应全部交由Spring管理,从而简化开发代码;
一、IOC
控制权翻转,对象的创建、初始化、销毁全部交由Spring管理;通过动态组件注册、bean对象初始化管理、依赖注入、
bean对象初始化前后进行次要业务组装实现
1.组件配置文件
1)xml形式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean class = "com.test.bean.Test" id = "test">
<property name ="id" value="1"></property>
<property name ="name" value="10"></property>
</bean>
2)注解形式
@Configuration修饰的类就相当于一个配置文件
@Configuration//相当于配置文件
public class ApplicationConfig {
//表示xml里面的bean标签value是ID值,这里value中可以是多个值逗号隔开,任何一个值都可以表示这个对象
@Bean(value={"t1","t2"})
public Test test1(){
return new Test();
}
}
3)获取方式
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ApplicationConfig.class);
System.out.println("Spring 容器启动了。。。");
Test t =(Test)context.getBean("t1");
2.组件注册
1)@bean: 标识将一个Java类交给Spring管理,@Bean要在【配置类】使用
- 默认时,以@Bean修饰的bean对象对应的关键字是【方法名】
- 如果在@Bean指定bean对象对应关键@Bean(value={"a1","a2"}),此时bean对象在Spring容器对应关键字就不是【方法名】,是a1或则a2
- 所有通过@Bean修饰生成的bean对象默认的情况下都是单例
- 对于单例的bean对象,可以通过@Lazy延缓变对象被创建时机
//这个注解专用于单例模式bean对象,此时bean对象不会在spring容器启动时被创建的,
//只有在一个用户来访时才会被创建
@Lazy
@Bean
public Test test(){
return new Test();
}
- bean在生命周期中监听bean对象
(1)可以指定初始化和销毁的方法
//bean类
public class Test {
public void init(){
System.out.println("实列化对象被初始化");
}
public void destory(){
System.out.println("实列化对象被销毁");
}
}
@Configuration//相当于配置文件
public class ApplicationConfig {
@Bean(initMethod="init",destroyMethod="destroy")
public Test test(){
return new Test();
}
}
(2)让bean类文件同时实现InitializingBean接口与DisposableBean接口.根据这两个接口提供的监听方法,来监听当前类的bean的实例化时机和销毁时机
public class Test2 implements InitializingBean,DisposableBean{
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("Test2对象被销毁");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("Test2对象初始化");
}
}
(3)在类中指定方法上添加这两个注解,来指定监听bean对象被实例化和销毁的时机@PreDestroy& @PostConstruct
public class Test3 {
public Test3(){
System.out.println("构造方法被调用");
}
@PostConstruct
public void init(){
System.out.println("Test3对象被初始化");
}
@PreDestroy
public void destroy(){
System.out.println("Test3对象被销毁");
}
}
2)@ComponentScan:自动将指定包下的【类】加载到Spring容器
(@Controller,@Service,@Resposity,@Compoent);@ComponentScan 要在【配置类】使用
可以将某些类排除在Spring容器之外(excludeFilters属性)
可以将某些类添加到Spring容器之内 (includeFilters属性)
FilterType:扫描过滤策略
- ANNOTATION 根据注解进行过滤(@Controller,@Service,@Resposity,@Compoent)
- ASSIGNABLE_TYPE 根据指定类型
- ASPECTJ表达式过滤
- REGEX根据正则表达式过滤
- CUSTOM,根据开发人员自行定义过滤规则
@ComponentScan(value="com.test.beans",excludeFilters={
@Filter(type=FilterType.ANNOTATION,
value={Controller.class,Service.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,
value={Test01.class}
})
//扫描com.test.beans包下类,排除注解@Controller的类,根据指定类型排除类Test01
@Configuration//相当于配置文件
public class ApplicationConfig {
}
//
@ComponentScan(value="com.test.beans",useDefaultFilters=false,includeFilters={
@Filter(type=FilterType.ANNOTATION,
value={Controller.class,Service.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,
value={Test01.class}
})
//扫描com.test.beans包下类去掉默认的过滤规则,扫描@Controller@Service注解的类,根据指定类型扫描类Test01
@Configuration//相当于配置文件
public class ApplicationConfig {
}
自定义扫描策略如下
/**
**自定义扫描策略
**实现TypeFilter接口.然后重写TypeFilter接口中match方法
**/
public class CustomerFilter implements TypeFilter {
public boolean match(MetadataReader arg0, MetadataReaderFactory arg1) throws IOException {
//获取当前bean关联的注解类型
AnnotationMetadata annotationMetadata = arg0.getAnnotationMetadata();
String classname = annotationMetadata.getClassName();//获取类名
//当前类上修饰的注解类型全路劲名
Set<String> annotationTypes = annotationMetadata.getAnnotationTypes();
System.out.println();
for(String str:annotationTypes){
System.out.println(str+"3543545");
}
//获取当前bean类的类型信息
ClassMetadata classMetadata = arg0.getClassMetadata();
String cn =classMetadata.getClassName();
System.out.println("---"+cn);
if(cn.contains("er")){
System.out.println("满足要求得类"+cn);
return true;
}
return false;
}
}
@ComponentScan(value="com.test.beans",useDefaultFilters=false,
includeFilters={
@Filter(type=FilterType.CUSTOM,
value={CustomerFilter.class})
})
@Configuration//相当于配置文件
public class ApplicationConfig2 {
}
3)@Scope:标识使用单例还是多例模式创建对象,在【配置类】使用,修饰【方法名】,默认单例
@Scope("prototype"):标识多例模式创建对象
@Scope("singleton"):标识单例例模式创建对象
4)@Conditional:按照指定条件来决定bean组件是否会在SpringIoc容器中被注册,在【配置类】使用,修饰【方法名】
Conditionnal注解中使用一个使用一个数组,这个数组存放的就是自定义判断条件,开发人员可以通过实现Condition接口,来定义自判断条件.
@Conditional({自定义条件类型.class})
//linux系统下才实列化对象
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String systemName = context.getEnvironment().getProperty("os.name");
if(systemName.contains("Linux")){
return true;
}
return false;
}
}
//windows系统下才实列化对象
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String systemName = context.getEnvironment().getProperty("os.name");
if(systemName.contains("windows")){
return true;
}
return false;
}
}
//配置类
@Configuration
public class ApplicationConfig {
@Conditional({LinuxCondition.class})
@Bean
public Test test(){
return new Test();
}
}
//测试类
public class TestMain {
public static void main(String[] args) {
//1.获得Spring容器对象
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ApplicationConfig.class);
//2.获得在Spring容器已经注册bean对象,可以发现在windows上运行Test对象未被实列化
String beanNames[]= context.getBeanDefinitionNames();
for(String beanName:beanNames){
System.out.println(beanName);
}
}
}
5)@import:指定bean导到SpringIOC容器中的一种方式,相当于 spring 配置文件中的 import 标签 ,一般在引入其他配置类时,可以不用再写@Configuration 注解
//指定JdbcConfig类加入Spring IOC作为配置类
@Import(value="com.test.bean.JdbcConfig.class")
@Configuration//相当于配置文件
public class ApplicationConfig {
}
或者通过实现ImportSelector自定义选择器
//自定义查询器
public class MyImport implements ImportSelector{
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//添加两个类
String array[] = {"com.test.beans.Test1","com.test.beans.Test2"};
return array;
}
}
//配置文件
@Import(MyImport.class)
@Configuration
public class ApplicationConfig {
}
6)FactoryBean是Spring容器提供的一种注册bean的方式,通过它来获得组件的bean的对象以及bean对象的单例或则多例的形态
//实现FactoryBean接口
public class MyFactoryBean implements FactoryBean<Test1>{
//获取实例对象
public Test1 getObject() throws Exception {
// TODO Auto-generated method stub
return new Test1();
}
//获取对象类型
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Test1.class;
}
//此方法不重写默认是单列
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}
}
//配置类
@Configuration
public class ApplicationConfig {
@Bean
public MyFactoryBean getMyFactoryBean(){
return new MyFactoryBean();
}
}
7)@AutoWired:自动转配(DI)
- 多个bean存在时,优先使用【类型名】进行赋值
- 多个bean存在时,可以是@Qualifier指定将某一个bean对象赋值给属性
@Autowired
@Qualifier("userServiceImpl")
private UserService userService;
- @AuotWired(required=false)
@Autowired注解的时候默认是@Autowired(required=true),表示注入的时候,该bean必须存在,否则就会注入失败;
@Autowired(required=false)表示忽略当前要注入的bean,一般再微服务开发过程中,因为模块分开,可能实现类是在另外一个模块中,此时需要用到这个,否则会装配失败报错
- 多个bean存在时,可以使@Primary指定优先用于赋值的bean(使用@Primary导致@Qualifier失效)
@Primary//表示优先实列话
@service
public class UserService implements IUserService {
}
8)@Resource
@Resource其实跟@AutoWired一样的功能,只是提供方不一样,@AutoWired是spring框架中提供的注解,而@Resource是javax.annotation包 提供,JSR250 规范实现
注入方式
@Autowired优先按照类型byType注入
@Resource默认按byName自动注入,也提供按照byType 注入,两个属性name和type
当找不到与名称匹配的 bean 时才按照类型进行装配,但是需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配
9)@inject
在javax.inject包 中,JSR330 规范实现的,与@Resource即@Autoware一样,根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named; 可以作用对象在setter方法、构造方法、字段上
@Inject标注通过optional参数来定义注入的接口是否需要注入的实现类,默认情况必须显示声明注入接口的实现。
10)@value
给基本类型和 String 类型注入值 ,可以使用占位符获取属性文件中的值
@Value(“${name}”)//name 是 properties 文件中的 key
private String name;
11)@PropertySource
加载 properties 配置文件,编写在类上面 ,相当于 context:property-placeholder 标签
属性value[]:用于指定properties文件路径,如果在类路径下,需要写上classpath
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
}
3.BeanPostProcessor后置处理器实现
BeanPostProcessor是一个接口,主要用于在bean对象初始化前后,做一些辅助功能
接口中包含的方法
postProcessBeforeInitialization:bean被初始化之前工作
postProcessAfterInitialization:被初始化之后工作
//定义自己的process
public class MyBeanPostProcess implements BeanPostProcessor{
public MyBeanPostProcess(){
System.out.println("构造方法被调用");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("初始化前"+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("初始化后"+beanName);
return bean;
}
}
//加入的bean容器中
@Configuration//相当于配置文件
public class ApplicationConfig3 {
@Bean
public MyBeanPostProcess myBeanPostProcess(){
return new MyBeanPostProcess();
}
}
//测试
public class TestMain3 {
public static void main(String[] args) {
//1.获得Spring容器对象
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ApplicationConfig3.class);
System.out.println("Spring 容器启动了。。。");
//此时容器已启动初始化bean对象会执行MyBeanPostProcess中方法
}