bean中公共属性抽取出来,统一配置
<bean class="com.cj.Animal" id="animal"><property name="category" value="犬科"/></bean><bean class="com.cj.Dog" id="dog1" parent="animal"><property name="name" value="小黑"/><property name="age" value="1"/></bean><bean class="com.cj.Dog" id="dog2" parent="animal"><property name="name" value="小黄"/><property name="age" value="1"/></bean>
java配置抽取公共属性:RootBeanDefinition
,GenericBeanDefinition
,
public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();rootBeanDefinition.setBeanClass(Animal.class);MutablePropertyValues pValues = new MutablePropertyValues();pValues.add("category","猫科");rootBeanDefinition.setPropertyValues(pValues);ctx.registerBeanDefinition("parent",rootBeanDefinition);GenericBeanDefinition cbd = new GenericBeanDefinition();cbd.setBeanClass(Cat.class);MutablePropertyValues cvalues = new MutablePropertyValues();cvalues.add("name","小花");cbd.setPropertyValues(cvalues);cbd.setParentName("parent");ctx.registerBeanDefinition("child",cbd);ctx.refresh();Cat cat = ctx.getBean("child",Cat.class);System.out.println("cat = " + cat);}
父子容器
同一个容器不允许相同的名字的bean同时出现,,如果两个相同名字的bean,通过两个不同的xml注入容器,,后面注入的bean会覆盖掉前面的那一个,,, 也可以设置属性ctx.setAllowBeanDefinitionOverriding(false);
不让覆盖。。。
解决办法:
写两个容器,,,,或者写成父子容器
子容器能获取父容器中的bean,但是父容器不能获取子容器的bean
public static void main(String[] args) {ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext();// 容器初始化,,没有传参数,不会自己初始化parent.refresh();ClassPathXmlApplicationContext consumer = new ClassPathXmlApplicationContext("consumer.xml");ClassPathXmlApplicationContext merchant = new ClassPathXmlApplicationContext("merchant.xml");// consumer.setParent(parent);// consumer父容器,merchant.setParent(consumer);// 设置完parent后,刷新容器merchant.refresh();RoleService r1 = merchant.getBean(RoleService.class);com.cj.merchant.RoleService r2 = merchant.getBean(com.cj.merchant.RoleService.class);System.out.println("r1 = " + r1);System.out.println("r2 = " + r2);// getBeanNameForType 只会在当前容器找,,,getBean会找父容器String[] s1 = merchant.getBeanNamesForType(RoleService.class);String[] s2 = merchant.getBeanNamesForType(com.cj.merchant.RoleService.class);System.out.println(Arrays.toString(s1));System.out.println(Arrays.toString(s2));}
包扫描
注入方式:
@Autowired
: 去spring容器中找某个类型
的Bean,去注入- 构造器注入,,创建一个spring的bean,会调用构造方法,构造方法需要另一个bean,,spring就会查找是否有这个bean,如果存在,会直接使用
@Controller
public class UserController {private UserService userService;public UserController(UserService userService) {this.userService = userService;}
}
- set方法上面加@Autowired : 看起来有点多余,实际上也是官方推荐的一种写法,,有了set方法,相当于提供了一个途径,,注入bean,,避免注入的bean是空指针。。如果没有set方法,就只能从spring容器中拿需要注入的对象
包扫描,会扫描指定包下面 @Service,@Component,@Controller,@Repository,@Configuration注解的类
<context:component-scan base-package="com.cj.scan"/>
扫到的类会被注册到spring容器中,,名字为类名的首字母小写
spring容器注入bean之后, 可以通过@Autowired要,也可以通过构造方法要
spring官方推荐我们使用构造器注入,而不是@Autowired,,
原因:一个类,可以注册到容器中,,也可以自己new出来使用。。。 但是一个类里面如果有@Autowired,注入了别的bean,,,然后使用new方法创建一个bean,,,,里面注入的bean就是空指针,,并且没有设置这个注入的bean的方法,,,
如果使用的是构造器注入,,,那么在new对象的时候,构造函数能够传入一个需要注入的bean,,防止用户忘记初始化属性,进而导致空指针
如果同时存在多个构造器,使用@Autowired 去指定到底使用哪个构造器去注入
默认情况下,扫描器会扫到所有的bean,,也可以通过配置,让其扫描部分bean…use-default-filter
为true
表示所有都扫描,,为false
表示一个都不扫描
<context:component-scan base-package="com.cj.scan" use-default-filters="true"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/></context:component-scan>
java配置: @ComponentScan
默认是扫描当前包下面的所有注解
@Configuration
@ComponentScan(basePackages = "com.cj.scan",useDefaultFilters = true,excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class}))
public class JavaConfig {
}
属性值的注入,spring加载配置文件
xml配置:
<context:property-placeholder location="classpath:db.properties"/><!-- ${xxx} 表示从spring中要这个value--><bean class="com.cj.DataSource" id="dataSource"><property name="url" value="${db.url}"/><property name="username" value="${db.username}"/><property name="password" value="${db.password}"/></bean>
java配置:
@PropertySource
导入属性值
@Value
: 从spring中要这个属性值
@Configuration
@PropertySource("classpath:db.properties")
public class JavaConfig {@Value("${db.url}")private String url;@Value("${db.username}")private String username;@Value("${db.password}")private String password;@BeanDataSource dataSource(){DataSource ds = new DataSource();ds.setUrl(url);ds.setUsername(username);ds.setPassword(password);return ds;}
}