1.@Configuration
使用这个注解来告诉Spring这是一个配置类,来替代原来的
2.@Bean
使用这个注解将一个对象实例注册进IOC容器中作为一个bean,默认的bean id为访问名,也可以显示指定id以及init、destroy方法,如@Bean(name = "sunwukong",initMethod = "init",destroyMethod = "destroy")
除了可以在注解中指定init、destroy方法外,还可以通过实现InitializingBean与DisposableBean来实现bean的初始化与销毁逻辑。
3.@ComponentScan
在原来的Spring xml配置文件中需要配置
来表示将这个包下的带有@Controller、@Service、@Repository、@Component
的类都注册到IOC容器里面。
现在可以在@Configuration
标注的配置类(相当于原xml配置文件)上标注@ComponentScan(value = "com.xxx")
里面可以添加excludeFilters = {} 、includeFilters = {}等用于过滤,@ComponentScans(value= {@ComponentScan})
可以写多个。
4.@Filter
在上面说到的excludeFilters、includeFilters数组中可以添加@Filter注解的过滤器。如
excludeFilters = {
@Filter(type=FilterType.Annotation,classes={Controller.class,Service.class},useDefaultFilters=false)
}
includeFilters = {
@Filter(type=FilterType.Annotation,classes={Controller.class,Service.class})
}
5.@Scope
在@Bean
将实例注入IOC时,可以通过@Scope设置4种模式。
singleton(单例)、prototype(原型)、request(同一个请求一个实例)、session(同一个会话一个实例)。默认是单例,对象为启动时创建,为饿汉式。若设置为prototype则对象为每次获取时创建,为懒汉式。
6.@Lazy
单实例bean可以标注此注解,用于将默认的饿汉式变为懒加载即第一次获取对象时创建。
7.@Conditional
这个注解根据条件来注册bean,可以放在方法上或者类上(满足条件类中的所有都会生效),下面是例子:
// 配置类
@Configuration
public class MainConfig {
@Bean("sunwukong")
@Conditional({LinuxCondition.class})
public Person persion01(){
return Person.builder().name("孙悟空").age(18).build();
}
@Bean("zhubajie")
@Conditional({WindowsCondition.class})
public Person persion02(){
return Person.builder().name("猪八戒").age(17).build();
}
}
// 自定义condition条件
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = ctx.getEnvironment();
String osName = env.getProperty("os.name");
return osName.contains("Windows");
}
}
// 自定义condition条件
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = ctx.getEnvironment();
String osName = env.getProperty("os.name");
return osName.contains("Linux");
}
}
8. @Import
自己写的组件使用@Component``@Controller``@Service``@Dao
来标注
第三方的组件使用@Bean
来注册
如果嫌写@Bean
麻烦,可以使用@Import
直接导入组件,默认id为全类名。@Import({A.class,B.class})
参数可以是数组同时导入多个类。
9.@Import
通过ImportSelector注册bean
可以自定义导入什么样的组件。
// 自定义importSelect
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// annotationMetadata参数可以获取注解等值
// 不要返回null
return new String[]{"com.zmz.al.bean.Red","com.zmz.al.bean.Yellow"};
}
}
// 配置类中注解导入
@Import({Color.class, MyImportSelector.class})
10.@Import
通过BeanDefinitions手动注册
自定义一个MyBeanDefinationRegistrar
public class MyBeanDefinationRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 判断是否含有黄色以及红色,有的话添加绿色
boolean hasYellow = registry.containsBeanDefinition("com.zmz.al.bean.Yellow");
boolean hasRed = registry.containsBeanDefinition("com.zmz.al.bean.Red");
if (hasYellow && hasRed) {
// 创建一个beanDefination
RootBeanDefinition green = new RootBeanDefinition(Green.class);
// 可以设置bean的name
registry.registerBeanDefinition("green",green);
}
}
}
配置类@import
中加入MyBeanDefinationRegistrar.class
@Import({Color.class, MyImportSelector.class, MyBeanDefinationRegistrar.class})
11.通过BeanFatory注册
// 新建一个类实现一个FacotryBean的接口
public class ColorFactoryBean implements FactoryBean {
@Override
public Color getObject() throws Exception {
return new Color();
}
@Override
public Class> getObjectType() {
return Color.class;
}
@Override
public boolean isSingleton() {
// true为单例,false为原型
return true;
}
}
// 将这个新的类注册到IOC容器
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
// 测试类
@Test
public void registryTest(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
可以看到,使用ioc可以根据name获取bean,如果有&
符号表示获取的是工厂本身,如果不加&
符号则获取的是具体的对象。
12. @PostConstruct
bean的生命周期的控制注解,在bean创建之后,赋值之后,进行调用。
13. @PreDestroy
bean的生命周期的控制注解,在bean的销毁之前进行调用。
@Component
public class Dog {
private String name;
private Integer age;
@PostConstruct
public void postConstruct(){
System.out.println("dog postConstruct ...");
}
@PreDestroy
public void preDestroy(){
System.out.println("dog preDestroy...");
}
}
14.使用BeanPostProcessor控制bean的生命周期
// 新建一个dog类
public class Dog {
private String name;
private Integer age;
@PostConstruct
public void postConstruct(){
System.out.println("dog postConstruct ...");
}
@PreDestroy
public void preDestroy(){
System.out.println("dog preDestroy...");
}
public void init(){
System.out.println("dog init...");
}
public void destroy(){
System.out.println("dog destroy...");
}
}
// 配置类中@Bean注册dog bean并标明init、destroy方法
@Bean(name = "dog",initMethod = "init",destroyMethod = "destroy")
public Dog dog(){
return new Dog();
}
// 构建beanProcessor类
@Component
public class MyBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前处理beanName:"+beanName+",bean:"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后处理beanName:"+beanName+",bean:"+bean);
return bean;
}
}
最后的执行顺序为
postProcessBeforeInitialization
,postConstruct
,init
,postProcessAfterInitialization
,preDestroy
,destroy
15.@Value
给bean赋值,1)可以是基本数值;2)可以使用Spring表达式SPEL,#{};3)使用${}读取配置文件中的值或者运行环境变量中的值。可以放在全局变量或者方法参数上。
16.PropertySource(value="classpath:person.properties")
使用该注解加载外部配置文件保存到运行的环境变量中,然后再使用@Value
读取配置文件。
17. @Autowired
、@Qualifier
默认按照类型去寻找IOC容器中的组件。如何同一类型的找到了多个,那么默认就根据属性名去寻找,如private ADAO aDao;
就根据aDao这个名称去寻找。还可以显示的指定使用@Qualifier("aDao")
注解来指定具体的名字。如何IOC中没有这个组件的情况下,可以在@Autowired(required=false)
标明是非必须的。
@Autowired
可以标注在方法上,表示其中的参数会通过类型去IOC中找到对应的bean。如set方法,有参构造器方法。
还可以标注在参数上public void aaa(@Autowired A a){}
,标在有参构造器上如果参数为1个时,可以省略。
@Bean
时方法中的参数也可以省略@autowired
注解,自动会去IOC容器中寻找bean。
18.@Primary
注册bean时,同类型多个bean中可以在其中一个标明此注解,来作为一个首选项,这样依赖注入@Autowired
的时候就可以优先拿到首选的bean了。注意@Qualifier
优先级大于@Primary
。
19.@Resource
是Java规范的依赖注入的注解,而@Autowired
是Spring的注解。
@Resource
默认按照组件名称进行装配。或者显示的@Resource(name="aDao")
来指定具体的bean。不能结合@Qualifier
、@Primary
注解,且不能使用required=false属性。
20.@Inject
是Java规范的依赖注入的注解,但是使用时需要引入一个javax.inject的包。
21.Spring底层Aware的使用
自定义组件想要使用Spring底层的组件时,可以实现xxxAware接口再进行使用。
22.@Profile
可以添加在方法上或者类上。
给组件添加标识,满足条件的bean才能被注册到IOC容器之中。默认@Profile("default")
的会被注册。
1)使用配置文件中的spring.prifiles.active=xxx来指定现在使用的环境标识,
2)通过JVM参数-Dspring.prifiles.active=xxx来指定
3)使用编码来指定
// 先准备两个环境的Bean
@Configuration
public class ProfileConfig {
@Profile("eat")
@Bean
public Person baigujing(){
return new Person("白骨精",17);
}
@Profile("mary")
@Bean
public Person nverguoguowang(){
return new Person("女儿国国王",18);
}
@Profile("mary")
@Bean
public Person kongquegongzhu(){
return new Person("孔雀公主",16);
}
}
// 测试类中
public class ProfileTest {
@Test
public void profileTest(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext();
ioc.getEnvironment().setActiveProfiles("mary");
ioc.register(ProfileConfig.class);
ioc.refresh();
String[] names = ioc.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
可以看到“eat组”的白骨精没有注册进来,“mary组”的孔雀公主、女儿国国王注册进来了。
23. aop相关注解
1.切面类与被切的业务逻辑类都应该使用IOC容器管理
2.给切面类一个注解@Aspect
标记为切面类
3.切面类中使用注解@Pointcut("execution(public int com.zmz.al.util.MathUtil.*(..))")
编写切入点表达式来赋值切入点的位置
4.@Before("pointCut()")
、@After("com.zmz.al.log.LogAspect.pointCut()")
、@AfterReturning(value="pointCut()",returning = "ret")
、@AfterThrowing(value="pointCut()",throwing = "e")
来编写切入点的前、后、返回后、异常后的生命周期自定义函数。
5.自定义的生命周期函数可以使用JoinPoint jp来获取切点相关的参数,如函数名称、函数参数列表等,这个参数一定要写在参数列表的第一位,还可以在注解中传入value、returning、throwing等属性值。
6.@EnableAspectJAutoProxy // 开启切面自动代理,一般在配置类中开启切面自动代理功能
@Aspect
public class LogAspect {
// 切入点表达式
@Pointcut("execution(public int com.zmz.al.util.MathUtil.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void logStart(JoinPoint jp){
Object[] args = jp.getArgs();
System.out.println(jp.getSignature().getName()+"@Before运行,参数列表是:"+ Arrays.asList(args));
}
@After("com.zmz.al.log.LogAspect.pointCut()")
public void logEnd(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"@After运行");
}
@AfterReturning(value="pointCut()",returning = "ret")
public void logReturn(JoinPoint jp,Object ret){
System.out.println(jp.getSignature().getName()+"@AfterReturning运行正常返回,结果是:"+ret);
}
@AfterThrowing(value="pointCut()",throwing = "e")
public void logException(JoinPoint jp,Exception e){
System.out.println(jp.getSignature().getName()+"@AfterThrowing运行异常,异常为:"+e);
}
}
24.声明式事务注解
1.将DataSource的事务管理器注册到IOC容器中,整合mybatis时会自动注册。
2.@Transactional
在方法上添加、@EnableTransactionManagement
在配置类上添加开启事务功能。
3.当方法中报异常时,会调用DataSource的事务管理器自动回滚数据库相关操作。
FAQ
1.在测试@Value
注解的时候,报了Could not resolve placeholder '' in value "${}"这样的错
进一步检查发现配置文件没有打包进入到target目录,查找之后是因为自己在pom.xml文件中配置了这个导致的。
pom
而这这个标签是用来指示idea将该模块打包成pom,所以,项目在启动编译时没有把配置文件同步到target目录下,项目运行时也拿不到配置文件的信息。