新建一个maven工程,引入依赖
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
dependency>
dependencies>
引入spring-context之后发现spring-core、spring-bean、spring-aop、spring-context、spring-expression、都引入进来了,这是因为spring-context内部依赖了其他几个包所以一同引了过来。
项目结构目录如图所示,创建三个空的bean,无需属性和方法。
MyConfig类
/**
* @Configuration 注解标志该类为配置类,配置bean有三种方式
*/
@Configuration
public class MyConfig {
/**
* 直接装配
*/
@Bean(name = "myBean")//名字默认为方法名
public MyBean createMyBean(){
return new MyBean();
}
/**
* 通过FactoryBean来装配
* 你会发现我们new的是一个JeepFactoryBean但是返回的却是Jeep
*/
@Bean(name = "jeep")
@Scope(value = "prototype")//scope默认为单例,改为prototype为多例
public JeepFactoryBean createJeepFactoryBean(){
return new JeepFactoryBean();
}
/**
* 通过factory 装配
* 注入一个CarFactory,Spring容器会自动从容器中找相应类型的bean注入进去
*/
@Bean
public CarFactory createCarFactory(){
return new CarFactory();
}
@Bean(name = "car")
public Car createCar(CarFactory carFactory){
return carFactory.createCar();
}
}
JeepFactoryBean需实现FactoryBean并实现他的三个方法
package com.yjj.factory;
import com.yjj.bean.Jeep;
import org.springframework.beans.factory.FactoryBean;
public class JeepFactoryBean implements FactoryBean{
@Override
public Jeep getObject() throws Exception {
return new Jeep();
}
@Override
public Class> getObjectType() {
return Jeep.class;
}
@Override
public boolean isSingleton() {
return true;//true为单例模式,false不是单利模式
}
}
CarFactory
public class CarFactory {
public Car createCar(){
return new Car();
}
}
测试类
public class App {
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println(context.getBean(MyBean.class));
System.out.println(context.getBean("myBean"));
System.out.println(context.getBean(Jeep.class));
System.out.println(context.getBean("jeep"));
System.out.println(context.getBean("&jeep"));//获取factoryBean本身
System.out.println(context.getBean(JeepFactoryBean.class));//获取factoryBean本身
System.out.println(context.getBean(Car.class));
System.out.println(context.getBean("car"));
}
}
以下是输出
com.yjj.bean.MyBean@5d20e46
com.yjj.bean.MyBean@5d20e46
com.yjj.bean.Jeep@709ba3fb
com.yjj.bean.Jeep@709ba3fb
com.yjj.factory.JeepFactoryBean@3d36e4cd
com.yjj.factory.JeepFactoryBean@3d36e4cd
com.yjj.bean.Car@6a472554
com.yjj.bean.Car@6a472554
有时候在初始化和销毁bean时我们想做一些刺激的事情,可以通过以下三种方式
public class Cat implements InitializingBean,DisposableBean {
/**
* bean初始化时候
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("-----init1-----");
}
/**
* bean销毁时
* @throws Exception
*/
@Override
public void destroy() throws Exception {
System.out.println("-----destroy1-----");
}
}
@Bean(initMethod = "init",destroyMethod = "destroy")
public Dog createDog(){
return new Dog();
}
public class Bird{
@PostConstruct
public void init(){
System.out.println("----init3----");
}
@PreDestroy
public void destroy(){
System.out.println("----destory3-----");
}
}
在获取bean时效果如下
-----init1-----
----init2----
----init3----
com.yjj.bean.MyBean@448ff1a8
com.yjj.bean.MyBean@448ff1a8
com.yjj.bean.Jeep@7f77e91b
com.yjj.bean.Jeep@6328d34a
com.yjj.factory.JeepFactoryBean@145eaa29
com.yjj.factory.JeepFactoryBean@15bb6bea
com.yjj.bean.Car@8b96fde
com.yjj.bean.Car@8b96fde
com.yjj.bean.Cat@2d2e5f00
com.yjj.bean.Dog@1e67a849
com.yjj.bean.Bird@57d5872c
--show--
com.yjj.service.UserService@667a738
----destory3-----
----destory2-----
-----destroy1-----
这是我们通常使用的一种方式,在bean类上方加上@Component、@Controller、@Service、@Repository注解,该类就会被自动注入Spring容器,当我们需要在别的类注入该bean时,只需要在属性上加上@Autowired注解即可,甚至不需要写get、set方法,我们通过@AutoWired注解注入bean时,自动通过类型装配,如果Spring容器中该类型的bean有两个,会选取name=属性名首字母小写的bean注入。
但是当你手动通过context获取bean时,需要显式指定获取哪一个bean否则Spring会不知道到底注入哪个bean而报错,如下我们在UserService上加入@Service注解,此时会在Spring容器注入一个name为userService的bean,我们再在MyConfig类再创建一个bean
@Bean
@Primary//此注解为当有多个UserService类型的bean时,此为注入对象
public UserService createUserService(){
return new UserService();
}
如果不加primary会报错
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yjj.service.UserService' available: expected single matching bean but found 2: userService,createUserService
解决方法
除了上述的@Primary注解,还可以在使用bean时加上@Qualifier注解指定使用哪一个bean,当出现同名的bean时,那其实就是一个bean,emm。。就是你用了@Component注解,又同时手动去装配了一个bean,name指定成bean类的首字母小写,name其实这两个是同一个bean。
也可以使用@Resource注解注入bean,同时@Inject注解也可以注入bean但是@Inject注解不是jdk自带的,需要引入jar包。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class,User.class, UserService.class, UserDao.class);
该类除了此构造方法还提供了一个扫描包的构造方法,在构造函数里传入一个包名,Spring会去自动扫描该包下带@Component、@Service、@Controller、@Repository的注解类,或者是在配置类中配置的bean并注入Spring容器。
还可以通过@ComponentScan注解添加扫描包basePackage=“包名”,还可以添加排除扫描类excludeFilters,排除有五种方式你可以去研究一下。
实现这个接口的两个方法可以在每个bean实例化之前和之后做一些处理,spring容器每实例化一个bean,都会执行一次该方法
实现BeanDefinitionRegistryPostProcessor
在postProcessBeanDefinitionRegistry方法
BeanDefinitionBuilder bdb=BeanDEfinitionBuilder.rootBeanDfinition(BeanName.class);
bdb.addPropertyValue("name","yinjunjie");
registry.registerBeanDefinition("person",bdb.getBeanDefinition());