@Configuration
类似之前通过xml配置信息。
public class MainTest {
public static void main(String[] args) {
// 加载配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
// bean默认名称是方法名为bean的名称,没找到抛异常。@Bean(value="")优先级高于方法名
// Person person1 = (Person) applicationContext.getBean("person");
// System.out.println(person1);
Person person1 = (Person) applicationContext.getBean("person1");
System.out.println(person1);
// 两个条件满足情况下才能找到
// Person person2 = (Person)applicationContext.getBean("person", Person.class);
// System.out.println(person2);
Person person3 = (Person)applicationContext.getBean("person1", Person.class);
System.out.println(person3);
}
}
@Configuration
public class MainConfig {
@Bean
public Person person1() {
return new Person(1,"罗超群");
}
}
@ComponentScan
扫描指定包并过滤指定的bean加载到容器。提供includeFilter和excludeFilter,过滤类型有:
- FilterType.ANNOTATION 根据注解过滤
- FilterType.ASSIGNABLE_TYPE 指定类
- FilterType.CUSTOM 自定义过滤器,需要实现TypeFilter
- FilterType.REGEX 正则匹配
@Configuration
@ComponentScan(value = "com.lcq.source.code.spring.annotation",
includeFilters = {},
excludeFilters = {
// 过滤指定注解
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// 指定类过滤
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {LcqSourceCodeService.class}),
// 自定义过滤
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}),
// Lcq开头的类
@ComponentScan.Filter(type = FilterType.REGEX, pattern = {"Lcq*"})
})
public class MainConfig {
@Bean
public Person person1() {
return new Person(1,"罗超群");
}
}
public class MyTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
// 获取当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类的资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("----" + className);
if (className.contains("Lcq")) {
return true;
}
return false;
}
}
public static void commpontScan() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
// 获取注入的bean,会将CommpontScan定义包下面所有加了Controller、Service、Commpont、Configuration等注解的类加载到容器
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName:beanNames) {
System.out.println(beanName);
}
}
public static void main(String[] args) {
// configuration();
commpontScan();
}
@Scope
bean的作用域,有:
- singleton 单实例(默认),ioc启动的时候会调用方法创建对象放到容器中,以后每次调用都从容器中获取实例
- prototype 多实例,IOC启动的时候不会调用方法创建对象放到容器中,每次获取的时候才会创建
- request 同一次请求创建一个实例
- session 同一个session创建一个实例
@Configuration
@ComponentScan(value = "com.lcq.source.code.spring.annotation",
includeFilters = {},
excludeFilters = {
// 过滤指定注解
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// 指定类过滤
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {LcqSourceCodeService.class}),
// 自定义过滤
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}),
// Lcq开头的类
@ComponentScan.Filter(type = FilterType.REGEX, pattern = {"Lcq*"})
})
public class MainConfig {
@Scope(value = "prototype")
@Bean
public Person person1() {
System.out.println("#####给容器中添加Person");
return new Person(1,"罗超群");
}
}
public static void scope() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person1 = applicationContext.getBean(Person.class);
Person person2 = applicationContext.getBean(Person.class);
System.out.println(person1 == person2);
}
public static void main(String[] args) {
// configuration();
// commpontScan();
scope();
}
#####给容器中添加Person
#####给容器中添加Person
false
@Lazy
单实例容器启动会创建,懒加载可以让bean第一次使用的时候创建
@Conditional
根据条件判断是否加载bean,自定义的类需要继承Condition
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String osName = environment.getProperty("os.name");
if (osName.contains("windows")) {
return false;
}
return true;
}
}
@Import
自己定义的类可以用@Service等注解
@Bean可以引用别人写的类。
@Import快速导入一个组件
@ImportSelector
自定义选择要导入的类,需要继承ImportSelector,返回值为类路径+类名的数。
可以使用ImportBeanDefinitionRegistrar:
public class ImportBeanRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
BeanDefinition beanDefinition = new RootBeanDefinition(House.class);
beanDefinitionRegistry.registerBeanDefinition("house", beanDefinition);
}
}
也可以通过FactoryBean定义bean,打印容器中的实例并不是factoryBean,而是factoryBean里定义的繁星,如果要获取factoryBean本身需要使用&+beanName
public class LcqFactoryBean implements FactoryBean<Child> {
@Override
public Child getObject() throws Exception {
return new Child("yang");
}
@Override
public Class<?> getObjectType() {
return Child.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
public static void factoryBean() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Object objInstance = applicationContext.getBean("lcqFactoryBean");
// class com.lcq.source.code.spring.annotation.bean.Child
System.out.println(objInstance.getClass());
Object objInstance2 = applicationContext.getBean("&lcqFactoryBean");
// class com.lcq.source.code.spring.annotation.factoryBean.LcqFactoryBean
System.out.println(objInstance2.getClass());
}
@Bean
定义bean,提供initMethod和destroy方法,分别在初始化的时候和销毁的时候执行。如果是单实例,初始化方法在容器启动时候执行,容器关闭的时候会destroy;如果是多实例,获取这个bean时执行,容器关闭并不会调用destroy。除了initMethod和destroy方法,想要初始化和销毁还可以通过InitializingBean和DisposableBean。
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod = "initCar", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
@PostConstruct
bean创建完成并且属性赋值完成执行
@PreDestroy
bean销毁之前执行
Bean实现BeanPostProcessor可以在bean初始化之前和初始化之后执行业务。
@Autowire
按类型自动装配
@Primary 没有使用Qualifier的情况下优先装配
@Qualifier 如果同一个类型的Bean定义了多个的情况下,可以根据名称使用哪个bean
@Resource 按名称自动装配,jdk里的注解
@Inject 自动装配,注解里面没有属性。需要导入javax.inject包
AOP
- @Aspect 定义切面
- @Pointcut 定义作用点
- @Before 作用点执行前
- @After 作用点执行后
- @AfterReturning 返回时候执行
- @AfterThrowing 抛异常时执行
- @Around 环绕,可以修改返回值
- @EnableAspectJAutoProxy 表示可以用aop
@Component
public class MathCalculator {
public Integer add(int i,int j) {
System.out.println("div运算进行中,i="+i+",j="+j);
// throw new NullPointerException();
return i+j;
}
}
@Aspect
public class LogAspects {
@Pointcut("execution(public Integer com.lcq.source.code.spring.annotation.aop.MathCalculator.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
System.out.println("运算开始"+joinPoint.getArgs()
+","+joinPoint.getKind()
+","+joinPoint.getSignature()
+","+joinPoint.getSourceLocation()
+","+joinPoint.getStaticPart()
+","+joinPoint.getTarget()
+","+joinPoint.getThis()
);
}
@After("pointCut()")
public void logEnd(JoinPoint joinPoint) {
System.out.println("运算结束"+joinPoint.getArgs()
+","+joinPoint.getKind()
+","+joinPoint.getSignature()
+","+joinPoint.getSourceLocation()
+","+joinPoint.getStaticPart()
+","+joinPoint.getTarget()
+","+joinPoint.getThis()
);
}
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(Object result) {
System.out.println("运算正常返回,result="+result);
}
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(JoinPoint joinPoint, Exception exception){
System.out.println("运算异常,exception="+exception);
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
Object obj = joinPoint.proceed();
// 修改返回值
obj = 10;
return obj;
}
}
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
@Bean
public MathCalculator calculator() {
return new MathCalculator();
}
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}
执行结果:
运算开始[Ljava.lang.Object;@4d5d943d,method-execution,Integer com.lcq.source.code.spring.annotation.aop.MathCalculator.add(int,int),org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@3270d194,execution(Integer com.lcq.source.code.spring.annotation.aop.MathCalculator.add(int,int)),com.lcq.source.code.spring.annotation.aop.MathCalculator@235834f2,com.lcq.source.code.spring.annotation.aop.MathCalculator@235834f2
div运算进行中,i=1,j=2
运算结束[Ljava.lang.Object;@4d5d943d,method-execution,Integer com.lcq.source.code.spring.annotation.aop.MathCalculator.add(int,int),org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@3270d194,execution(Integer com.lcq.source.code.spring.annotation.aop.MathCalculator.add(int,int)),com.lcq.source.code.spring.annotation.aop.MathCalculator@235834f2,com.lcq.source.code.spring.annotation.aop.MathCalculator@235834f2
运算正常返回,result=10
关键类:
- BeanPostProcessor
- AutowiredAnnotationBeanPostProcessor
- ApplicationContextAwareProcessor 判断类是实现了哪个Aware(EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware等),先把bean转成对应的Aware并调用对应的set方法赋值。