浅谈spring IOC容器中装配bean
spring容器中装配bean的方式可以归纳为以下三种:
1.基于xml配置;
2.基于注解;
3.Java配置类形式;
基于xml配置:
1.bean的命名:spring配置文件不允许出现两个相同id的bean,但可以出现两个相同name的bean,多个name相同的 bean则取后面声明的那个,因此应尽量使用id而非name, 如果id和name都没有指定,spring默认将全限定名作为 bean的名称,这时可以通过getBean("com.XXX.AAA")获取AAA这个bean,尽量不要这么干
2.属性注入:首先注意,所有spring装配的bean都必须提供一个无参并且是public的构造,属性注入是根据set方法注入 的,所以如果属性的set方法是setIDCode,那么在xml中必须 这样写<property name="IDCode" value="xx">,原因在 于JavaBean规范中规定,xml中属性变量名可以大写开头,不过必须满足变量的前两个字母要么全部大写要么全部小 写的要 求,否则变量名不合法将会报Error setting property values
3.构造函数注入:
3.1.按类型匹配入参
3.2.按索引匹配入参
3.3.联合使用类型和索引匹配入参(保险,推荐),如下:
4.工厂方法注入(非静态工厂方法和静态工厂方法)
5.注入参数详解:
5.1.字面值:对于property里面的值如果带有& > <等特殊符号需进行特殊处理,处理方式有两种,第一种加上xml特殊标签<![CDATA[]]>,在中括号中写字面值,第二种方式是加特殊符号对应的转义字符
5.2.引用其他bean:通过<ref parent="car">引用父容器中的bean,这种场景适合在在当前容器bean不满足业务场景时,需要引入父容器中的bean时,现实中很少会出现这样的场景
5.3.内部bean,如果某个bean只被一个bean引用,则可以在property中定义那个bean,这个bean可以不需要id,即使提供也会被忽略,然而作用于域只能是默认的prototype
5.4.如果想要为某个属性注入null值,必须使用专用的<null/>标签,否则spring会解析为空字符串
5.5.级联属性,如果Boss类中有car这个属性,则可以在xml文件中<property name="car.price" value=123/>,一般不会这么干
5.6.集合类型属性
5.6.1.List:使用<list>标签,Java类型是List或者数组都可以这样写
5.6.2.Set:使用<set>标签
5.6.3.Map:使用<map></map>
假如某一个map的key和value都是对象,则可以使用<ref>标签
6.简化配置方式
6.1.字面值属性,即将value标签的值写到property中(针对有些标签有不同,如上面的entry标签只需把key和value值写到entry里即可),注意,如果使用简化配置就不能只用<![CDATA[ ]]>标签处理特殊字符,只能使用xml转移字符
6.2.引用对象属性,<ref bean="xxx">
6.3.使用p命名空间,以前的<property name="brand" value="奔驰">,可以直接在bean元素中写p:brand="奔驰",如果是对象,则p:<属性名>-ref="xxx";(正因为p命名空间的属性名是可变的,所以p命名空间没有对应的Schema定义文件,也就无需在xsi:schemaLocation 中为p命名空间指定Schema定义文件,只需声明xmlns命名空间即可)
7.方法注入:如果想要在singletor Bean 获取一个prototype Bean时使用(需要用到CGLib类包)
8.bean之间的关系
8.1.继承:
8.2.依赖:可以通过depends-on属性来显示指定bean前置依赖的bean,前置依赖的bean会在本bean实例化之前创建好,有多个前置依赖的bean中间可以用逗号或者空格分开
9.bean的作用域
9.1.singletor作用域:spring将bean的默认作用域定位singletor,任何时候通过容器的getBean方法返回的都是同一个bean,默认情况下,容器启动的时候将多有的singletor的bean实例化并缓存在容器中,如果用户不希望容器启动的时候实例化可以通过lazy-init属性进行控制(如果该bean被其他bean所引用那么将会忽略lazy-init属性)
9.2.prototype作用域:每次通过容器的getBean方法返回的都是一个新的bean,默认情况下容器启动的时候不会实例化prototype的bean,此外,spring将bean交给调用者,就不再管理它的生命周期了
9.3.与web应用环境相关的bean的作用域:首先需要在web.xml中配置RequestControllerListener监听器,以监听http的请求事件
9.3.1.request作用域:每次的http请求都创建一个新的bean,请求完毕就销毁
9.3.2.session作用域:session中的所有请求都共享一个bean,session结束就销毁
9.3.3.globalSession作用域:只适合在Portle的web应用中使用
9.4.作用域依赖问题:如果需要将web相关作用域的bean注入到singletor或者prototype的bean中,此时我们需要用到spring Aop的动态代理功能<aop:scoped-proxy>(aop是根据这个http请求对应的线程去获取bean的,因为web容器中,一个http请求是对应一个独立的线程)
基于注解的配置
1.使用注解定义bean
@Respository:用于dao实现类进行标注
@Service:用于对service实现类进行标注
@Controller:用于对控制器类进行标注
@Component:不是以上三种情况的时候就使用该注解定义bean
2.扫描注解定义的bean
如果不设置use-default-filters="false" 将会扫描base-package路径中所有标有注解的bean, type的值可以是annotion,assignable,aspectj,regex,custom
3.自动转配bean
3.1.使用@Autowired进行自动注入,默认按照类型注入
3.2.使用@Autowired的required,将该属性值设为false,则没有找到注入的bean也不会报错
3.3.使用@Qualifier指定注入bean的名称,当接口的实现类有多个时候需要这么干
3.4.对延迟依赖注入的支持:对bean进行延迟依赖注入,要注意@Lazy注解必须同时标注在属性和目标bean上面,否则不会生效
3.5.对标注注解的支持
@Resource:按照名称匹配,若没有指定一个名称则默认按照变量名或者方法名匹配陪bean
@Inject:按照类型匹配,但是没有required属性
4.Bean作用范围及生命过程方法
4.1. @Scope指定bean的作用域
4.2. @PostConstruct:bean初始化时执行的方法,可以是多个
4.3. @PreDestroy:容器销毁前执行的方法,可以是多个
4.4.执行过程:容器先调用bean的构造方法实例化bean,在执行@Autowired进行自动注入,然后分别执行标注了@PostConstruct,在容器关闭时执行@PreDestroy
基于Java类的配置
1.通过Configuration标注一个类,然后通过@bean标注一个方法实例化bean,适合实例化很复杂的场景
2.通过@Configuration类启动spring容器,通过AnnotationConfigApplicationContext来完成