spring容器
一、组件注册
1给容器中注册组件
1.1包扫描:
-@ConmponetScan(value=" ") value中放包扫描的路径
作用:这个注解用于批量注册bean到spring容器中
常用参数:
value:指定需要扫描的包 比如:com.java.dao;
basePackages:作用和value但不能存在设置,可二选一;
basePageClasses:指定一些类,spring容器自动扫描这些类所在的包和包中的子类;
includeFilters:过滤器,用来配置哪些被扫描出来的那些类会被作为组件注册到容器中;
excludeFilters:过滤器,和includeFilters相反,用来对扫描的类排除,被排除的类不会注册到容器中
lazyInit:是否延迟初始化被注册到Bean
@ComponentScan(value = "java.dao",excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),//按照注解排除 @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {UserMapper.class}),//按照类型排除 @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {})//自定义排除规则 class里是自定义排除规则的类,实现TypeFilter接口 })
1.2容器中注册组件
-@Component、@Service、@Repository、@Controller:把普通的实体类实例化到spring容器中,相当于配置文件的<bean id="" class=""/>,标注的类,主要是自己写的类
-@Bean:主要导入第三方的包里面的组件
-@Import:快速给容器中导入一个组件
Import(类名):容器中就会自动注册这个组件,id默认是组件的全名;
ImportSelector:该注解是一个接口,返回需要一个全类名的数组,需要实现接口,可以在该接口的实现类中自定义逻辑返回需要导入的组件,返回值就是导入到容器中的组件全类名
ImportBeanDefinitionRegistrar:手动注册bean;
@Import(MyImportSelector.class) //MyImportSelector类实现ImportSelector接口, //返回需要导入的组件的全类名的数组 public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"top.nnzi.bean.User"}; } }
-@Conditional:主要标注在bean上,按照一定的条件判断,满足条件给容器中注册一个bean
1 public class MyCondition implements Condition { 2 3 /** 4 * 5 * @param context 判断条件能使用的上下文(环境) 6 * @param metadata 注解信息 7 * @return true为允许注册,false反之 8 */ 9 @Override 10 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 11 //获取ioc使用的beanFactory 12 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); 13 //获取类加载器 14 ClassLoader classLoader = context.getClassLoader(); 15 //获取当前环境信息 16 Environment environment = context.getEnvironment(); 17 //获取bean定义的注册类 18 BeanDefinitionRegistry registry = context.getRegistry(); 19 20 //逻辑代码编写,返回判断值. 21 22 return false; 23 } 24 }
-使用spring提供的FactoryBean:spring用来生产Bean到spring容器中,FactoryBean是用来创建比较复杂的bean
默认获取到的是工厂bean调用getObject创建的对象,T getObject():返回是一个对象,这个对象会添加到容器中
isSingletion(): 返回是一个 T:F 若是T 这个Bean是单例 在容器中保存一份,反之是多例每次都会创建一个新的Bean
要获取到工厂bean本身,需要给id前面加个&标识
public class UserFactoryBean implements FactoryBean<User> { /** * * @return 返回一个对象,该对象会被添加到容器 * @throws Exception */ @Override public User getObject() throws Exception { return new User(); } /** * * @return 返回对象的类型 */ @Override public Class<?> getObjectType() { return User.class; } /** * * @return 是否为单实例创建 true表示单实例 */ @Override public boolean isSingleton() { return false; } }
-@Scope():设置组件的作用域
prototype:多实例 ioc容器启动并不会去调用方法创建方法在容器中,而是每次获取时才会调用方法创建对象
singleton:单实例 ,默认值 ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就去容器中拿
二、生命周期
1.bean的生命周期
1.1bean的创建—初始化—销毁过程
bean创建:
单实例:在容器启动时创建
多实例:每次获取时创建
bean初始化:成员变量赋值,各种增强,对象创建完成,赋值,调用初始化方法
bean销毁:
单实例:关闭容器时
多实例:容器不会管理这个bean,容器不会调用销毁方法
1.2自定义初始化和销毁方法
-通过@Bean指定initial-method和destory-method;
-通过bean实现InitaializingBean接口定义初始化逻辑:在beanFatory将所有属性设置完以后调用;
-通过让bean实现DisposableBean接口定义销毁逻辑:在beanFactory销毁单实例对象前调用;
-通过使用JSR250注解标注在方法上
@PostConstucor:在bean创建完成并属性赋值成功来执行初始化方法;
@PreDestroy:在容器销毁bean之前通知我们进行清理工作
-通过BeanPostProcessor接口在bean初始化前后做一些工作
postProcessBeforeInitialization:在初始化之前进行一些工作
postProcessAfterInitialization:在初始化之后进行一些工作
public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
2.属性赋值
-@Value
基本数值:
@Value("张三")
prvate String name;
可以写在SpEL #{ }:
@Value("#{20-2}")
prvate Int age;
可以写 ${ },取出配置文件中的值【properties】,在运行环境变量里面的值
@PropertySource(Value={"classpath:/person.properites"})含义就是属性的来源读外部配置文件的K/V保存到运行环境中
@Value("${person.nickName}")
prvate String nickName;
3.自动装配
-@AutoWird:自动注入,可以标注来构造器、参数、方法、属性;
-@Resource:和@Autowired注解类似,都用来声明需要自动装配的bean,区别在于@Autowired是类型驱动的注入,而@Resource是名称驱动的注入;
-自定义组件:需要实现Aware接口,在创建对象的时候会调用接口规定的方法注入相关组件,把spring底层的一些组件注入到自定义的bean中Aware的功能都是是由AwareProcessor处理的,判断了实现那个Aware接口然后将bean转换成该类型调用的set方法,将容器底层组件注入
@Override @Nullable public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareInterfaces(bean); return null; }, acc); } else { invokeAwareInterfaces(bean); } return bean; } private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
-@Profile:可以根据当前环境,动态的激活和切换一系列组件的功能,开发环境、测试环境、生产环境
-加入了环境标识的Bean只有这个环境被激活的时候才能注入到容器中,默认时default环境
--写在配置类上,只有是指定环境的时候,整个配置类所有的配置才会生效
---没有标注环境标识的bean在任何环境下都加载
运行时如何指定运行环境
-命令行参数,通过在虚拟机参数位置制定和Dspring.profiles.active=xxx来指定运行环境,标注了该环境的bean会被配置进容器中
--程序内指定:创建一个applicationContext—>设置需要激活的环境applicationContext.getEnvironment().setActiveProfiles("")—>注册主配置类applicationContext.register(xxx.class)—>启动刷新容器,applicationContext.refresh();
四、AOP
-AOP:动态代理指程序运行期间动态的将某段代码切入到指定方法的指定位置进行运行和编辑
4.1AOP的使用
-导入AOP坐标sping-aspects
-定义一个业务逻辑类,在业务逻辑运行的时候将日志进行打印
-前置(@Before):logStart在目标方法(div)运行之前运行参数列表传入jionPoint可获取到方法的相关属性,且该参数必须方法第一个参数,否则无法识别
-后置通知(@After):logEnd方法 (div)运行之后运行无论方法正常结束还是异常结束
-返回通知(@AfterReturning(returning 可以指定封装返回值的参数)):logReturn在目标方法(div)正常返回之后运行
-异常通知(@AfterThrowing):logException 在目标方法上出现异常后运行
- 环绕通知(@Around):动态代理,手动推进目标方法运行 (joinPoint.proceed())
-给切面类的目标方法标注何时何地运行(切点表达式)
-将切面类、目标类、业务逻辑类都加入到容器中
-告诉spring‘那个是切面类,给切面类加一个@Aspect
-需要给配置类加@EnableAspectJAutoProxy开启基于注解的aop模式
@Aspect public class LogAspects { @Pointcut("execution(public int top.nnzi.aop.AOPTest.*(..))") public void pointCut(){}; @Before("pointCut()") public void logStart(JoinPoint joinPoint) { System.out.println(joinPoint.getSignature().getName()+"运行,参数列表是:"+ Arrays.asList(joinPoint.getArgs())); } @After("pointCut()") public void logEnd (JoinPoint joinPoint) { System.out.println(joinPoint.getSignature().getName()+"结束"); } @AfterReturning(value = "pointCut()",returning = "result") public void logReturn (JoinPoint joinPoint,Object result) { System.out.println(joinPoint.getSignature().getName()+"正常返回,结果为:"+ result); } @AfterThrowing(value = "pointCut()",throwing = "exception") public void logException (JoinPoint joinPoint,Exception exception) { System.out.println(joinPoint.getSignature().getName()+"抛出异常:"+exception); } }
@Configuration @ComponentScan(value = "top.nnzi.bean") @EnableAspectJAutoProxy public class MyConfig { @Bean public AOPTest aopTest () { return new AOPTest(); } @Bean public LogAspects logAspects () { return new LogAspects(); } }
4.2AOP的原理
4.2.1@EnableAspectJAutoProxy
-Import(AspectJAutoProxyRegister.class)给容器导入一个AspectJAutoProxyRegistrar.class(利用AspectJAutoProxyRegistrar自定义给容器中注册Bean)
-执行registerBeanDefinitions方法中的:AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
-给容器中注册"internalAutoProxyCreator"=AnnotationAwareAspectJAutoProxyCreator的bean(BeanDefinition);
4.2.2AnnotationAwareAspectJAutoProxyCreator继承关系
AnnotationAwareAspectJAutoProxyCreator extends
AspectJAwareAdvisorAutoProxyCreator extends
AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartlinstantiationAwareBeanPostProcessor,BeanFactoryAware
关注后置处理器(在bean初始化前后做事情)(SmartInstantiationAwareBeanPostProcessor)自动装配beanFatory(BeanFactoryAware)
五、声明式事务
-在方法上标注@Transactuinal注解表示当前方法是一个事务方法
-@EnableTransactionManagement开启基于注解的事务管理功能
-配置事务管理器来控制事务
@Bean public PlatformTransactionManager platformTransactionManager (DateSource dateSource) { return new DataSourceTransactionManager(dateSource); }
六、BeanPostProcessor
-BeanPostProcessor:bean的后置处理器,bean创建对象初始化前后进行拦截工作
-BeanFactoryPostProcessor:beanFactory的后置处理器,在beanFactory标注初始化后调用,所以bean的定义已经保存加载到beanFactory,但bean的实例没有创建
-流程:
-ioc容器创建对象
--invokeBeanFactoryPostProcessors:执行BeanFatoryPostProcessors
-Spring[]postProcessorNames=beanFactory.getBeanNamesForType(BeanFactoryPsotProcessor.class,true,false);找到所有的postProcessor的名字执行方法
-在初始化创建其他组件前面执行
-BeanDefinitionRegistryPostProcessor:
-是beanFactoryPostProcessor的子接口,BeanDefinitonRegistry是Bean定义信息的保存中心,BeanFactory是按照其中保存的bean的定义信息创建Bean的实例。
-postProcessBeanDefinitionRegisty方法,在所有bean定义信息将要被加载到的,但bean实例还没创建,优先于BeanFactoryPostProcess执行,可以利用其容器中来添加组件
七、AppliocationListener
-ApplicationListener:监听容器中发布的事件,事件驱动模型的开发
-实现ApplicationListener< E extends ApplicationEvent >接口:监听ApplicationEvent及其子类的相关事件,只要容器中有相关事件发布,我们就能监听到这个事件,如
-ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件
-ContextClosedEvent:关闭容器发布这个事件
-或者自己发布事件:自定义发布一个事件 ioc容器.publishEvent(ApplicationEvent);
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
@EventListener(class={}):可以在普通业务逻辑组件的方法上标注该注解来监听事件。
浙公网安备 33010602011771号