Spring注解大纲

一、大纲

1.1 Spring IOC组件

Spring IOC组件

1.2 Spring AOP

Spring AOP

1.3 Spring声明式事务

Spring声明式事务

1.4 Spring注解之扩展

Spring注解之扩展

二、Spring IOC组件

2.1 Spring IOC注解方式

从Spring3.0 @Configuration用于定义配置类,可替换XML配置文件。被注解的类内部包含有一个或者多个@Bean注解的方法,并且这些方法将会被AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext类进行扫描,用于构建Bean定义,初始化Spring容器。

public class AnnotationBeanMethodApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanMethodConfigure.class);
        
        // 获取实例
        Common common = ctx.getBean("common", Common.class);
        OtherCommon otherCommon = ctx.getBean("otherCommon", OtherCommon.class);
        
        // 打印实例
        log.info("common = {}", common);
        log.info("otherCommon = {}", otherCommon);
        
        ctx.close();
    }
}

@Configuration
class BeanMethodConfigure {
	// 单实例的销毁是由容器管理
    @Bean(value = "common", initMethod = "init", destroyMethod = "destroy")
    public Common common() {
        return new Common();
    }

    // 多实例是销毁是由JVM执行
    @Scope(scopeName = "prototype")
    @Bean(value = "otherCommon", initMethod = "init", destroyMethod = "destroy")
    public OtherCommon otherCommon() {
        return new OtherCommon();
    }
}

2.1 @PostConstruct

@PostConstruct注解的用途:被注解的方法,在对象加载完依赖注入后执行。在构造函数之后,init()方法之前运行。
在Spring项目中,在一个Bean的初始化过程中,方法执行先后顺序为:Constructor > @Autowired > @PostConstruct。

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

2.2 @PreDestroy

@PreDestroy注解在方法上用作回调通知,表明实例正在被IOC容器删除(IOC容器关闭的时调用销毁)。带有@PreDestroy注解的方法通常用于释放它一直持有的资源。

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}

2.3 @ComponentScan

@ComponentScan注解通知Spring从哪里开始找到Bean,并且扫描特定注解标识的类载入IOC容器。

2.3.1 注解类

// 注意:虽然直接为ElementType.TYPE,但是只能注解到类上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 表明:@ComponentScan 可以在类上重复注解使用
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    // 01. 扫描的基础包
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};
    
    // 02. 指定多个类或接口的class,扫描时会在这些指定类和接口所属包进行扫描
    Class<?>[] basePackageClasses() default {};
    
    // 03. 对应Bean名称的生成器, 默认的是BeanNameGenerator
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    
    // 04. 提供Bean Scope范围特征解析器
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    // 05. 作用域代理
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    // 06. 控制符合组件检测条件的类文件, 默认是.class文件
    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
    
    // 07. 是否自动扫描注解@Component、@Repository、@Service或者@Controller的类
    boolean useDefaultFilters() default true;
    
    // 08. 指定包含指定规则的组件
    Filter[] includeFilters() default {};
    
    // 09. 指定排除指定规则的组件
    Filter[] excludeFilters() default {};
    
    // 10. 扫描到的类是都开启懒加载, 默认false
    boolean lazyInit() default false;
}

2.3.2 实现

@Configuration
@ComponentScan
(
		// 01. 扫描的基础包
		// 02. 指定类, 扫描时会在这些指定类和接口所属包进行扫描
		// 03. 指定包含指定规则的组件
		// 04. 指定排除指定规则的组件
		// 05. 关闭自动扫描注解@Component、@Repository、@Service或者@Controller的类
		// 注意:FilterType.CUSTOM需要设置includeFilters = false
        basePackages = "com.ioteye.spring.annotation.annotation.component.scan",
        basePackageClasses = {OtherService.class},
        includeFilters = @Filter(type = FilterType.CUSTOM, classes = PrintTypeFilter.class),
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Repository.class),
        useDefaultFilters = false
)
public class AnnotationComponentScanConfigure {

}

@Slf4j
class PrintTypeFilter implements TypeFilter {
        /**
         *
         * @param metadataReader 当前扫描类元数据信息Reader
         * @param metadataReaderFactory 容器元数据信息的工厂
         * @return 如果实例被过滤, 返回false, 否则返回true
         */
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) 
               throws IOException 
        {
                // 当前扫描类注解信息
                AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
                // 当前扫描类元数据信息
                ClassMetadata classMetadata = metadataReader.getClassMetadata();

                String className = classMetadata.getClassName();

                log.info("className = {}",  className);

                return true;
        }
}

2.4 @Filter

@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
    // 01. 过滤类型,枚举值为:
    // FilterType.ANNOTATION:指定注解
    // ASSIGNABLE_TYPE: 指定类的类型
    // ASPECTJ: ASPECTJ表达式
    // REGEX: 正则表达式
    // CUSTOM: 自定义规则, 需要实现TypeFilter接口, 只有在useDefaultFilters=false情况下才能触发
    FilterType type() default FilterType.ANNOTATION;

    @AliasFor("classes")
    Class<?>[] value() default {};

    @AliasFor("value")
    Class<?>[] classes() default {};

    // 02. 针对ASPECTJ的值进行设置的
    String[] pattern() default {};

}

2.5 @Conditional

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册Bean。

2.5.1 注解

// 01. 注解到类上, 满足条件时该类的Bean才会加入容器
// 02. 注解到方法上, 满足条件时该方法的Bean才会加入容器
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	Class<? extends Condition>[] value();

}

2.5.2 实现

@Configuration
public class AnnotationConditionConfigure {
    @Bean
    @Conditional(value = WindowsCondititon.class)
    public BillGates billGates() {
        return new BillGates();
    }
    
	class WindowsCondition implements Condition {
	    @Override
	    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
	        // 01. 获取IOC使用的beanFactory
	        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	        // 02. 获取类加载器
	        ClassLoader classLoader = context.getClassLoader();
	        // 03. 获取环境信息
	        Environment environment = context.getEnvironment();
	        // 04. 获取Bean定义的注册类
	        BeanDefinitionRegistry registry = context.getRegistry();
	        String env = environment.getProperty("os.name");
	
			// 05. 配置包含Win时才能满足条件
	        if (env.contains("Win")) {
	            return true;
	        }
	
	        return false;
	    }
	}
}

2.6 @Import

@Import只能用在类上,通过快速导入的方式把实例注入到Spring的IOC容器中。
@Import的三种用法主要包括:

  1. 直接Class数组
  2. ImportSelector
  3. ImportBeanDefinitionRegistrar

2.6.1 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

2.6.2 实现

@Import(
	{
	    Person.class, 
	    CustomizingImportSelector.class, 
	    CustomizingImportBeanDefinitionRegistrar.class
	}
)
public class AnnotationImportConfigure {

}

class CustomizingImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.ioteye.spring.annotation.common.entity.BillGates"};
    }
}

class CustomizingImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 
                                        BeanDefinitionRegistry registry) 
   {
        RootBeanDefinition definition = new RootBeanDefinition();
        definition.setBeanClass(Linus.class);

        registry.registerBeanDefinition("linus", definition);
    }
}

打印内容:

beanName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName = org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName = org.springframework.context.event.internalEventListenerProcessor
beanName = org.springframework.context.event.internalEventListenerFactory
beanName = annotationImportConfigure
beanName = com.ioteye.spring.annotation.common.entity.Person
beanName = com.ioteye.spring.annotation.common.entity.BillGates
beanName = linus

2.7 @Profile

Spring框架提供了多profile管理功能,可以使用@Profile功能来区分不同环境的配置。激活方式:

  • 通过ConfigurableEnvironment.setActiveProfiles(String...)以编程方式激活
  • 通过spring.profiles.active设置JVM系统属性值激活
  • 在集成测试中,通过@ActiveProfiles注解以声明方式激活配置
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
	String[] value();
}

class ProfileCondition implements Condition {
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		if (context.getEnvironment() != null) {
			// 检索Profile类型注释的所有属性
			MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
			if (attrs != null) {
				// 获取Profile的value属性值
				for (Object value : attrs.get("value")) {
					if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
						return true;
					}
				}
				return false;
			}
		}
		return true;
	}
}

三、AOP

AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

3.1 @EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;
}

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 注册AspectJAnnotationAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}

3.2 @Aspect

  • execution语法
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
  • Spring AOP注解
  • @Before:前置建议,在执行一个业务方法之前插入的切面
  • @AfterReturning:当一个方法正常运行后执行的切面
  • @After:当方法执行成功或者出现异常的时候都会执行切面
  • @Around:相当于一个AOP链,如果当前AOP执行后,就让下一个AOP执行
  • @AfterThrowing,如果在方法中有错误抛出,则执行此建议
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
public class LogAop {
	@Before("execution(public void com.spring.dao.impl.StudentDaoImpl.*(..))")
	 public void logBefore() {
	    log.info("方法执行之前转载日志");
	 }

	@AfterReturning("execution(public void com.spring.dao.impl.StudentDaoImpl.insert(..))")
	public void logAfterReturning() {
	    log.info("方法执行返回后载入日志");
	}

	@After("execution(public * com.spring.dao.impl.StudentDaoImpl.*(..))")
	public void logAfter() {
	    log.info("finally载入日志");
	}

	@Around("execution(public * com.spring.dao.impl.StudentDaoImpl.*(..))")
	public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
	    log.info("around建议载入日志, 时间:{}", new Date());
	    Object o = pjp.proceed();
	    return o;
	}

	@AfterThrowing("execution(public * com.spring.dao.impl.StudentDaoImpl.*(..))")
	public void logAfterThrowing() {
	    log.info("有参数异常载入日志, 时间:{}" + new Date());
	}
}

3.3 @Pointcut

标准的Aspectj Aop的pointcut的表达式类型是很丰富的,但是Spring Aop只支持其中的9种,外加Spring Aop自己扩充的一种一共是10种类型的表达式,分别如下:

  • execution:一般用于指定方法的执行,用的最多。
  • within:指定某些类型的全部方法执行,也可用来指定一个包。
  • this:Spring Aop是基于代理的,生成的bean也是一个代理对象,this就是这个代理对象,当这个对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
  • target:当被代理的对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
  • args:当执行的方法的参数是指定类型时生效。
  • @target:当代理的目标对象上拥有指定的注解时生效。
  • @args:当执行的方法参数类型上拥有指定的注解时生效。
  • @within:与@target类似,看官方文档和网上的说法都是@within只需要目标对象的类或者父类上有指定的注解,则@within会生效,而@target则是必须是目标对象的类上有指定的注解。而根据测试这两者都是只要目标类或父类上有指定的注解即可。
  • @annotation:当执行的方法上拥有指定的注解时生效。
  • bean:当调用的方法是指定的bean的方法时生效。
@Pointcut("@within(org.springframework.stereotype.Controller)")
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值