spring 注解开发
@Configuration
@Configuration //告诉spring这是一个配置类
给容器注册组件
非注解
<?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.ljq.bean.Person" id="person">
<property name="age" value="18"></property>
<property name="name" value="张三"></property>
</bean>
</beans>
注解
/**
* 给容器注册组件:
*1)、包扫描(@ComponentScan)+组件标注注解(@Controller/@Service/@Repository/@Component)
*2)、@bean[导入第三方包里面的组件]
*3)、@Import[快速给容器中导入一个主键]
* 1、@Import(要导入容器的主键):容器就会自动注册这个组件,id默认是全类名
* 2、ImportSelector:返回需要导入组件的全类名
* 3、ImportBeanDefinitionRegistrar:手动注册bean到容器中
* 4)使用Spring提供的FactoryBean(工厂Bean)
* 1、默认获取到的是工厂bean调用getObject创建的对象
* 2、要获取工厂bean本身需要给id前面加一个&
* &colorFactoryBean
*/
@Bean
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class MainConfig {
//给容器重注册一个Bean;类型为返回值的类型,id默认还是方法名作为id
@Bean("person") //id默认为方法名,也可在@Bean中设置
public Person person01(){
return new Person("list",20);
}
}
//测试
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean);
@controller@service@repository@component
@controller用来定义控制(dao)层的组件
@service用来定义业务层(service)的组件
@repository用来定义持久层(domain)的组件
@component用来定义不在上述范围内的一般性组件
上面组件的名称默认是类名的首字母小写,如果要重命名,则这样@controller("beanName")
@ComponentScan
@ComponentScan(value = "com.ljq") //要扫描的定义以上注解的包 加入bean容器
@ComponentScan(value = "com.ljq" ,includeFilters = {
//@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
} ,useDefaultFilters = false)
//@ComponentScan value:指定要扫描的包
// excludeFilters=Filter[],指定扫描时要排除的组件
// ANNOTATION:按照注解
// ASSIGNABLE_TYPE:按照给定类型
// ASPECTJ:使用ASPECTJ表达式
// REGEX:使用正则表达式
// CUSTOM:使用自定义规则
/**
* @ComponentScan(value = "com.ljq" ,excludeFilters = {
* @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})}) 排除Controller标签
*
*
*/
// includeFilters=Filter[],指定扫描时只需要包含那些组件
/**
* @ComponentScan(value = "com.ljq" ,includeFilters = {
* @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})} ,useDefaultFilters = false)
*/
自定义规则
public class MyTypeFilter implements TypeFilter {
/**
*MetadataReader:读取到的当前正在扫描的类的信息
*MetadataReaderFactory:可以获取到其他任何类信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源信息(类路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("-->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
@Scope
//@Scope 调整作用域,默认是单实例的
/**
* prototype:多实例的:ioc容器启动并不会去调用方法放在容器中
* 每次获取的时候才会调用方法创建对象
* singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放入ioc容器中
* 以后每次获取直接从容器(map.get)中拿
* request:同一次请求创建一次实例
* session:同一个session创建一个实例
*
*
*/
// @Scope("prototype") //控制作用范围
@Lazy
懒加载:
单实例bean:默认在容器启动的时候创建对象
懒加载:容器启动时不创建对象,第一次使用(获取时创建对象)
@Import
[快速给容器中导入一个主键]
-
1、@Import(要导入容器的主键):容器就会自动注册这个组件,id默认是全类名
在配置类中
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) //导入组件,id默认是全类名
-
2、ImportSelector:返回需要导入组件的全类名
public class MyImportSelector implements ImportSelector { //放回值就是要导入到容器中的主键全类名 //AnnotationMetadata:当前标注@Import注解的类的所有信息 public String[] selectImports(AnnotationMetadata annotationMetadata) { //方法不能返回null值 return new String[]{"com.ljq.bean.Blue","com.ljq.bean.Yellow"}; } }
-
3、ImportBeanDefinitionRegistrar:手动注册bean到容器中
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata:当前类的注解信息
* @param beanDefinitionRegistry:BeanDefinition注册类:
* 把所有需要添加到容器中的bean:调用
* BeanDefinitionRegistry.registerBeanDefinition手动注册
*/
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean definition = beanDefinitionRegistry.containsBeanDefinition("com.ljq.bean.Red");
boolean definition1 = beanDefinitionRegistry.containsBeanDefinition("com.ljq.bean.Blue");
if (definition&&definition1){
//指定bean定义信息,(bean的类型,bean。。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
//注册一个bean,指定bean名
beanDefinitionRegistry.registerBeanDefinition("rainBow",beanDefinition);
}
}
}
使用Spring提供的FactoryBean(工厂Bean)
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
public Color getObject() throws Exception {
System.out.println("................");
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
//是单例吗?
//true:这个bean是单例在容器中只会保存一份
//false:多实例,每次获取都会创建一个新的
public boolean isSingleton() {
return false;
}
}
需要在配置类中
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();//看到容器中所有的Bean
Blue bean = applicationContext.getBean(Blue.class);
System.out.println(bean);
//工厂Bean获取的是调用getObject创建的对象
Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
Object colorFactoryBean1 = applicationContext.getBean("colorFactoryBean");
Object colorFactoryBean2 = applicationContext.getBean("&colorFactoryBean");
ColorFactoryBean colorFactoryBean3 = applicationContext.getBean(ColorFactoryBean.class);
System.out.println(colorFactoryBean==colorFactoryBean1);
System.out.println("bean类型"+colorFactoryBean.getClass());
System.out.println("bean类型2"+colorFactoryBean2.getClass());
System.out.println("bean类型3"+colorFactoryBean2.getClass());
false
bean类型class com.ljq.bean.Color
bean类型2class com.ljq.bean.ColorFactoryBean
bean类型3class com.ljq.bean.ColorFactoryBean
-
1、默认获取到的是工厂bean调用getObject创建的对象
-
2、要获取工厂bean本身需要给id前面加一个&
&colorFactoryBean
bean的生命周期
bean的生命周期:
* bean创建---初始化---销毁的过程
* 容器管理bean的生命周期
* 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命的时候来调用我们自定义的初始化和销毁方法
*
* 构造(对象创建)
* 单例:容器启动时创建对象
* 多实例:每次获取时创建容器对象
* BeanPostProcessor.PostProcessorBeforeInitialization
* 初始化:
* 对象创建完成,并赋值好,调用初始化方法。。。
* BeanPostProcessor.PostProcessorAfterInitialization
* 销毁:
* 单实例:容器关闭时候,进行销毁
* 多实例:容器不会管理这个bean;容器不会调用销毁方法
1)、指定初始化和销毁方法
- // 基于配置文件的方式scope=“prototype” init-method="" destroy-method=""
- 通过@Bean指定init-method 和 destroy-method;
@Bean(initMethod = "init",destroyMethod = "destory")
public Car car(){
return new Car();
}
public class Car {
public Car(){
System.out.println("car constructor....");
}
public void init(){
System.out.println("car iit.....");
}
public void destory(){
System.out.println("car destory....");
}
}
2)、通过让bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑)
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat constructor....");
}
public void destroy() throws Exception {
System.out.println("cat .... destroy...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("cat..afterPropertiesSet...");
}
}
3)、可以使用JSR250:
-
@PostConstruct :在bean创建完成并且属性赋值完成,执行初始化
-
@PreDestroy :在容器销毁之前通知我们进行清理工作
@Component public class Dog { public Dog(){ System.out.println("Dog constructor..."); } //对象创建并赋值之后调用 @PostConstruct public void init(){ System.out.println("Dog...PostConstruct...."); } //在容器移除之前调用 @PreDestroy public void detory(){ System.out.println("Dog ....PreDestroy"); } }
4)、BeanPostProcessor:bean的后置处理器;
-
在bean的初始化前后进行一些处理工作:
-
PostProcessorBeforeInitialization:在初始化之前工作
-
PostProcessorAfterInitialization: 在初始化之后
/** * 后置化处理器:初始化前后进行处理工作 * 将后置处理器加入容器中 */ @Component public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { System.out.println("postProcessBeforeInitialization.."+s+"=>"+o); return o; } public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("postProcessAfterInitialization.."+s+"=>"+o); return o; } }
属性赋值@Value
//使用@Value赋值
//1、基本数值
//2、可以写SpEL:#{}
//3、可以写${}取出配置文件【properties】中的值(在运行环境变量中的值)
@Value("张三")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
person.nickName=小张三
//配置类中
//使用@PropertySource读取外部配置文件中的K/V保存到运行环境中;加载玩外部的配置文件以后使用${}取出配置文件的值
@PropertySource({"classpath:/person.properties"})