注解开发和配置文件开发转化说明和对比
原spring开发 | 注解开发 |
Spring 的配置文件 applicationContext.xml | @Configuration注解注释的类 |
bean的注入 <bean id="helloWorld" class="com.hd.spring.HelloWorld"> | @Bean 赋值还可以用@value注解赋值 @Bean person {
@Value("张三")
}
|
加载配置文件获取bean用 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); | ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); MainConfig这个类是@Configuration注释的类 |
原扫描包注入 <context:component-scan base-package="com.hd.cyz"></context:component-scan> <context:component-scan> 下可以拥有若干个 <context:include-filter> 和 <context:exclude-filter> 子节点 用指定节点<context:include-filter>配置时需要禁用<context:component-scan> 默认的全部扫描 <context:component-scan base-package="xxx.xxx" use-default-filters="false"> | @ComponentScans( @ComponentScan value:指定要扫描的包 FilterType.ASSIGNABLE_TYPE:按照给定的类型; useDefaultFilters 相当于标签中的use-default-filters="false"属性 默认true @ComponentScans中可以配置多个 @ComponentScan 需要扫描一个时用@ComponentScan 加的位置在配置类上 |
<!-- 具体的作用域需要在 scope 属性中定义 --> <bean id="XXX" class="com.XXX.XXXXX" scope="XXXX" /> singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例 prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例 request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效 session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效 globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效 其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。 如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。 | @scope完成bean的作用域配置默认是单例模式(singleton)如果需要设置的话可以修改对应值与以上提到的一致例如:@scope(“prototype”) |
在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法 | * 1)、指定初始化和销毁方法; @Bean(initMethod="init",destroyMethod="detory") |
应用外部文件并赋值 <context:property-placeholder location="classpath:dbconfig.properties" /> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> | 注解用在配置类上面@PropertySource(value={"classpath:/dbconfig.properties"}) 获取配置文件中的值 @Value("${key}")注解加在bean的属性上 |
@Profile注解(详情见下文) | |
<!-- 使 AspectJ 的注解起作用 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> | 开启基于注解的aop模式;@EnableAspectJAutoProxy |
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 启用事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"/> | 给方法上标注 @Transactional 表示当前方法是一个事务方法; @EnableTransactionManagement 开启基于注解的事务管理功能; 配置事务管理器来控制事务; //注册事务管理器在容器中 @Bean public PlatformTransactionManager transactionManager() throws Exception{ return new DataSourceTransactionManager(dataSource()); } |
给容器中导入组件的其他方法
@Import[快速给容器中导入一个组件]
* 1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
* 2)、ImportSelector:返回需要导入的组件的全类名数组; 需要自己写实现根据自己的需求装入组件
* 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
使用Spring提供的 FactoryBean(工厂Bean);
* 1)、默认获取到的是工厂bean调用getObject创建的对象
* 2)、要获取工厂Bean本身,我们需要给id前面加一个
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)
* 自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
* 把Spring底层一些组件注入到自定义的Bean中;
* xxxAware:功能使用xxxProcessor;
* ApplicationContextAware==》ApplicationContextAwareProcessor;
条件构造器编写Condition
@Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
条件构造器
public class LinuxCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO是否linux系统
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境信息
Environment environment = context.getEnvironment();
//4、获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器中的bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
自定义filter编写
实现 implements TypeFilter重写match方法
match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)参数说明
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类信息的
举例
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("hd")){
return true;
}
return false;
}
Profile用法详解
/**
* Profile:
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
*
* 开发环境、测试环境、生产环境;
* 数据源:(/A)(/B)(/C);
*
*
* @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
*
* 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
* 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
* 3)、没有标注环境标识的bean在,任何环境下都是加载的;
*/
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware //第三种获取配置文件的值{
@Value("${db.user}")//第一种获取配置文件的值
private String user;
private StringValueResolver valueResolver;//第三种获取配置文件的值
private String driverClass;//第三种获取配置文件的值
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{//第二种获取配置文件的值
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/prod");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {//第三种获取配置文件的值
// TODO Auto-generated method stub
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
上面是写配置文件写法
用法
//1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
//2、代码的方式激活某种环境;
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
//1、创建一个applicationContext
//2、设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev");
//3、注册主配置类
applicationContext.register(MainConfigOfProfile.class);
//4、启动刷新容器
applicationContext.refresh();
String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
for (String string : namesForType) {
System.out.println(string);
}
applicationContext.close();
}
spring注解开发开启aop
开启基于注解的aop模式;@EnableAspectJAutoProxy