通过组件扫描创建对象
话不多说,直接上代码:
package cn.codingfire.spring; import org.springframework.stereotype.Component; @Component public class UserMapper { }
package cn.codingfire.spring; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("cn.codingfire.spring") public class SpringConfig { }
接着进行测试,和上面其实是一样的:
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class); UserMapper bean = ac.getBean(UserMapper.class); System.out.println(bean); ac.close();
刚刚没有把跑的结果贴出来,这里贴出来给大家看看:
cn.codingfire.spring.UserMapper@52aa2946 Process finished with exit code 0
可以看到获取到的对象是真实存在的。 这里对关键部位做个说明:
@ComponentScan注解是执行组件扫描的关键,当创建AnnotationConfigApplicationContext对象时,传入的SpringConfig配置类添加了这个注解,Spring框架就会扫描配置下的包中的所有组件类,然后为组件创建对象并管理,而UserMapper类必须在@ComponentScan注解配置的包中,否则Spring框架找不到这个类,无法创建对象。@Component仅表示此类是一个组件类,但也很重要,没有此注解,将不会创建此对象。
@ComponentScan("cn.codingfire.spring")相当重要,这是扫描的路径,如果括号中内容变成,cn.codingfire,它下面有这些包:cn.codingfire.spring,cn.codingfire.controller,cn.codingfire.mapper,cn.codingfire.pojo等等,这些包统统都会被扫描到,这一点要注意,不要扫描不需要的包,对性能是有影响的。
另外,前面说过getBean扫描的方式,这里再次重申一遍:不指定beanName,默认的beanName都是类的首字母小写的名字,仅适用于类名中的第1个字母是大写,且第2个字母是小写的情况,否则,将传入完整的类名。一般我们指定beanName多一些,会更安全。
为@Component注解指定beanName案例:
@Component("userMapperBeanName")
关于@ComponentScan("xxxxxx")
我们点进去看下源码:
可以知道@ComponentScan("xxxxx")中的参数,如果传一个,可以不显示的指定默认参数名:value,如果需要配置多个属性,需要显示指定。
传入多个参数时,比如要扫描多个包的情况,我们看到
String[] value() default {};
说明它是一个数组类型的,可以传多个包名,但需要使用大括号:
@ComponentScan({"xxxxx"})
Spring Bean的作用域
前面提到,Spring这种创建管理对象的方式很像单例,所以:
我们通常认为,Spring Bean的作用域是单例的
单例的特点是:实例唯一,任何时候,类的实例对象只能有一个,创建出来后,需常驻内存,直到程序运行结束或者ApplicationContext调用了销毁的方法
上面也提到过,此单例非彼单例,莫要混为一谈,只是作用域的表现完全和单例一致
那么作用域是否可以修改呢?答案是肯定的。通过在@Bean注解之前添加过@Scope注解来改变其作用域,作用域有三类,默认是单例的:
singleton:单例的,这是默认值,在scopeName属性的源码上明确的说明了:Defaults to an empty string "" which implies ConfigurableBeanFactory.SCOPE_SINGLETON
prototype:原型,也就是非单例的
还有其它取值,都是不常用取值,可不用关心,自定了解即可
Spring Bean是预加载的,关于此,我们知道的还有一个懒加载,通过@Lazy来表示,如必要,可创建为懒加载的。@Lazy注解的value属性是boolean类型的,表示“是否懒加载” 。
预加载何懒加载,我不说,大家也应该知道这是什么意思,在其他语言中,我们很多时候使用懒加载来降低资源的损耗,但是在Java中略有不同,为了避免高并发时懒加载去创建对象出现问题,我们通常在Java只能够采用预加载的方式。
自动装配技术
什么是自动装配
Spring的自动装配是,当某个量需要被赋值时,可以使用特定的语法,使得Spring尝试从容器找到合适的值,并自动完成赋值其中最典型的代表是@Autowired注解,Spring会尝试从容器中找到生明的对象并初始化来为此属性赋值。
举个例子:
package cn.codingfire.spring; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("cn.codingfire.spring") public class SpringConfig { }
package cn.codingfire.spring; import org.springframework.stereotype.Component; @Repository public class UserMapper { public void insert() {} }