spring4 知识点
1 bean的 创建
1,直接在配置文件里面写一个带有@Bean注解的方法(返回值就是那个bean对象),(name等于 方法名)
@Bean还可以写在枚举上面
2,使用 FactoryBean 接口(三个方法分别是创建,类型,单例),需要把它加入到spring 容器管理,@Component 或者 @Bean
这时候 默认名字指向的是 FactoryBean 返回的元素对象实例。而不是 FactoryBean 对象的实例,使用 &默认名字 指向的FactoryBean 对象实例
单例模式的时候元素对象放在单例池中,当多例的时候每次通过FactoryBean 实例区获取一个新的单例对象。
/**
* FactoryBean 向Spring容器注册对象
*
* @Author ZHANGYUKUN
*/
@Component("goods")
public class GoodsFactoryBean implements FactoryBean<Goods> {
int i = 0;
/**
* 返回一个元素实例
* @return
* @throws Exception
*/
@Override
public Goods getObject() throws Exception {
Goods goods = Goods.randomGoods();
goods.setName("goodsName" + i++);
return goods;
}
/**
* 返回类工厂元素类型
* @return
*/
@Override
public Class<?> getObjectType() {
return Goods.class;
}
/**
* 选择多例模式
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
3,在 配置类里面可以 用一个 @Bean 方法的形参里面写入Spring 容器里面的 Bean 对象,这样会自动注入
@Bean
public String testParam( GoodsService getGood1) {
System.out.println("形式参数:" + getGood1 );
return "testParamRT";
}
备注:只有一个默认只有满足有且只有一个同类型的对象才能注入,否者随机注入一个,需要精确注入可以使用@Qualifier("name")
2 指定bean 的 初始销毁几种方法
1 bean 类继承 ,InitializingBean,DisposableBean 接口实现对应方法
2, 在配置注解上面指定 @Bean(destroyMethod="destroy",initMethod="afterPropertiesSet")
3,(jsr 250 的 注解) 在方法前写上 @PreDestroy(销毁前) 和 @PostConstruct(创建以后)
调用顺序 java >接口的>@Bean 指定的
@Bean(initMethod = "initMethod",destroyMethod = "destroyMethod")
public BeanLifecycle beanLifecycle( @Qualifier("getGood2") Goods getGood1) {
return new BeanLifecycle();
}
public class BeanLifecycle implements InitializingBean, DisposableBean {
@PostConstruct
public void postConstruct() throws Exception {
System.out.println("1 postConstruct 方法 ");
}
@PreDestroy
public void preDestroy() throws Exception {
System.out.println("4 preDestroy 方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("2 InitializingBean 接口的 afterPropertiesSet 方法 ");
}
@Override
public void destroy() throws Exception {
System.out.println("5 DisposableBean 接口的 destroy 方法");
}
public void initMethod() throws Exception {
System.out.println("3 initMethod 方法");
}
public void destroyMethod() throws Exception {
System.out.println("6 destroyMethod 方法 ");
}
}
3 spring bean属性的注入
@Primary ,@Autowired ,@Qualifier,@Resource 关系
1 同类的bean有多个实例 ,按照 类型获取的时候会获取代 @Primary 注解标注的那个
2 如果没有指定那么 @Primary那么@Autowired 默认会报错,但是可以通过 @Qualifier("name") 类指定注入实例的名字
@Autowired
@Qualifier("getGood1")
Goods goods;
3 @Resource 默认就是按照字段名字找优先(没写名字的时候默认名字是字段名字),如果找不到再按照类型,并且也可以指定 字段以外的名字 @Resource(name="getGood1"),但是@Resource 不能写在方法参数上, @Qualifier可以
@Resource,@Qualifier 都可以打破 @Primary的优先注入
4 spring的多例
@Scope("prototype") 修饰的@Bean 或者 @Component 表示这个类是多例对象(spring 管理的对象默认是单例的),或者实现FactoryBean接口
//--------------------------------@Scope的 多例---------------------------------------------------------
int i = 0;
@Bean
@Scope("prototype")
public Goods getScopeGoods() throws Exception {
Goods goods = Goods.randomGoods();
goods.setName("getScopeGoods" + i++);
return goods;
}
获取多例有2种办法
1 直接通过名字在容器中获取
/**
* 通过 @Scope 获取多例对象
*/
@Test
public void t4(){
logger.info("通过对象名字获取多例1:{}", SpringContextHoder.getContext().getBean("getScopeGoods") );
logger.info("通过对象名字获取多例2:{}", SpringContextHoder.getContext().getBean("getScopeGoods") );
logger.info("通过对象名字获取多例3:{}", SpringContextHoder.getContext().getBean("getScopeGoods") );
}
2 通过 ObjectFactory 获取(注解方式需要用这种)
@Autowired
ObjectFactory<Goods> getScopeGoods;
/**
* 通过ObjectFactory获取多例对象
*/
@Test
public void t6(){
System.out.println( getScopeGoods.getObject() );;
}
备注: ObjectFactory <T> 方式获取多例对象,最好指定名字,在单例多例并且,并且不只一个的时候可能会找不到不你想要的那个多例对象(@Primary 在不指定名字的时候优先级最高,如果没有指定@Primary的对象,那么ObjectFactory 是有效获取多例对象的),实现factoryBean 多例和@Scope 的多例都可以这样获
比如这样:
@Autowired
@Qualifier("goodsFactoryBean")
ObjectFactory<Goods> getScopeGoods;
5 AnnotationConfigApplicationContext(Config.class,UserFactoryBean.class) 的 方法里面 不仅仅 可以@Configuration标注的配置类 还可以写 带有注解的组件(@Component ,@Service @Controller @Repository,等等)
5 @Qualifier 对 @Autowired,@Inject(需要引入inject 包) 按照类型匹配进行修饰(按照名字选择)
@ComponentScan 指定扫描的包
备注:@Inject 注解已经现在默认不能用了, 它属于 JSR 330 标准
6 拿到 spring 容器
1 实现 ApplicationContextAware
这个方法其实就是在 BeanPostProcessor 里面判断是否实现了 ApplicationContextAware 接口 ,若果实现了,那么就掉指定方法设置 spring容器
2 构造方法的参数里面写 public SpringContext(ApplicationContext applicationContext,@Qualifier("user2") User user)
备注,这种方法只能有一个构造函数,多个不知道选那个,会默认选择无参数的那个 (如果没有无参数的那个会报错) spring 4.3 提供(spring4.3 默认会给会为 构造方法注入)
3 直接在任意spring 管理的类中注入 spring 容器 @Inject AnnotationConfigApplicationContext context;
4 不能通过getBean 的到
@Bean参数形参注入(貌似会循环注入)
//--------------------------------@Bean 形参获取 ApplicationContext---------------------------------------------------------
@Bean
public ApplicationContext getApplicationContext( ApplicationContext applicationContext) {
System.out.println( "通过形参获取applicationContext:" + applicationContext );
return applicationContext;
}
构造方法参数
@Component
public class MySpringApplicationContext {
private ApplicationContext context;
//webApplicationContext是默认容器的名字
public MySpringApplicationContext(@Qualifier("webApplicationContext") ApplicationContext context) {
this.context = context;
}
public ApplicationContext getContext() {
return context;
}
}
测试方法
@Autowired
MySpringApplicationContext mySpringApplicationContext;
@Autowired
@Qualifier("getApplicationContext")
ApplicationContext applicationContext;
/**
* 通过构造方法获取 ApplicationContent
*/
@Test
public void t8(){
//通过ApplicationContextAware获取
System.out.println( SpringContextHoder.getContext() );
//通过构造方法获取(@bean的 方法估计也行)
System.out.println( mySpringApplicationContext.getContext() );
//直接注入获取
System.out.println( applicationContext );
//这种方式不能获取
System.out.println( mySpringApplicationContext.getContext().getBeansOfType( ApplicationContext.class ) );
}
7 几个重要的 Factory的接口
BeanFactory,FactoryBean,ObjectFactory
1 BeanFactory spring的工厂类,它不是一种类的工厂(不是只返回一种类型),而是一个容器接口,通过这个容器接口我们可以拿到spring托管的对象。
2 FactoryBean 我们的工厂类,通过这个接口让spring给我们托管这个工厂类,从而产生 工厂里面的 对象(单例一般不需要,使用多例的时候可以借用这个 接口 来产生多例的实例对象)
3 ObjectFactory
多用于多例对象的获取, 用法:
@Autowired ObjectFactory<单例对象类型> 单例对象工厂;
8 几个重要的 postProcessor 接口
BeanPostProcessor ,BeanFactoryPostProcessor ,BeanDefinitionRegistryPostProcessor
执行顺序 BeanDefinitionRegistryPostProcessor >BeanFactoryPostProcessor >BeanPostProcessor
1 BeanPostProcessor
实现 BeanPostProcessor 的类可以对任何 spring管理的类的 初始化开始和完成进行监听,并且任意的修改 这个对象。
备注:我们可以通过 postProcessor 对server 类调用 做参数日志(返回一个代理对象,然后在方法调用前打印参数)
备注2: BeanPostProcessor 对所有spring管理的 类都生效。及其强大,能做的拓展及其的多
一个修改 goods 属性的 BeanPostProcessor 实现
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
//可以在spring托管的Bean 对象构造完成的前后 做一些处理,比如修改一些属性,甚至环一个实例
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if( beanName.equals("getGood1") ){
Goods goods1 = ((Goods)bean);
goods1.setName(goods1.getName() + "postProcessBeforeInitialization附加");
System.out.println( "postProcessBeforeInitialization:" + beanName +"::"+ bean );
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if( beanName.equals("getGood1") ){
Goods goods1 = ((Goods)bean);
goods1.setName(goods1.getName() + "postProcessAfterInitialization附加2");
System.out.println( "postProcessAfterInitialization:" + beanName +"::"+ bean );
}
return bean;
}
}
测试代码,打印修改以后的名字,打印已有的BeanPostProcessor 实现类有几个(加我写的那个一共16个)
/**
* 测试 BeanPostProcessor 修改对象属性
*/
@Test
public void t9(){
logger.info("BeanPostProcessor 修改goods的 名字:{}", goods.getName() );
logger.info("BeanPostProcessor 修改goods的 名字:{}", applicationContext.getBeansOfType(BeanPostProcessor.class).size() );
}
2 BeanFactoryPostProcessor
BeanFactoryPostProcessor 接口 可以拿到 所有bean 的 factroy 在 BeanPostProcessor 之前触发,这里获取到的是 spring容器对象,这时候其实没有初始化完成,如果这里获取bean,会导致bean 的提前初始化,在后面 BeanPostProcessor 执行的时候就不会在初始化这个类了(认为已经初始化完成)。
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, BeanPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor:" + beanFactory );
//这时候很多容器初始化没完成bean 如果用了,后面 BeanPostProcessor 的流程对应的 bean 会被跳过(估计认为已经初始化完成了),注释掉下面一行以后就会执行
System.out.println("MyBeanFactoryPostProcessor 获取对象:" + beanFactory.getBean("myGoods") );
}
//可以在spring托管的Bean 对象构造完成的前后 做一些处理,比如修改一些属性,甚至环一个实例
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if( beanName.equals("myGoods") ){
Goods goods1 = ((Goods)bean);
goods1.setName(goods1.getName() + "postProcessBeforeInitialization附加");
System.out.println( "MyBeanPostProcessor前:" + "修改参数" );
}
System.out.println( "MyBeanPostProcessor前:" + "修改参数:"+ "beanName" );
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if( beanName.equals("myGoods") ){
Goods goods1 = ((Goods)bean);
goods1.setName(goods1.getName() + "postProcessAfterInitialization附加2");
System.out.println( "MyBeanPostProcessor后:" + "修改参数");
}
return bean;
}
3 BeanDefinitionRegistryPostProcessor
可以动态的注册spring 的 bean 对象,甚至修改Bean 的定义,Bean的类型,能做的事情比 BeanPostProcessor还多 (BeanDefinitionRegistryPostProcessor 集成自 BeanFactoryPostProcessor 接口)
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//注册一个bean
RootBeanDefinition beanDefinition = new RootBeanDefinition(MyGoods.class);
//构造参数
//ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
// constructorArgumentValues.addIndexedArgumentValue(1, "user2");
// beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
//添加 名字是 myDefinitionObject 的 BeanDifinition
registry.registerBeanDefinition("myDefinitionObject",beanDefinition);
//查找一个bean(所有的bean都可以在这里找到)
System.out.println("有那些beanDefinition:"+ JSONObject.toJSONString( registry.getBeanDefinitionNames() ) );
BeanDefinition myDefinitionObject = registry.getBeanDefinition("myDefinitionObject");
//删除bean定义
registry.removeBeanDefinition( "myDefinitionObject" );
//在删除以后修改 myDefinitionObject 的 beanDifinition(类型都改了)
RootBeanDefinition beanDefinition2 = new RootBeanDefinition(Goods.class);
registry.registerBeanDefinition("myDefinitionObject",beanDefinition2);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
--------------------------------------------------------------------------------------------------------- 一些杂记------------------------------------------------------------------------------------------------------------------------
spring 的核心
ioc (容器+工厂)
aop ( 代理 + aspectj )
IOC 部分
ApplicationContext 的所有父接口都能干什么?
BeanFactory 的所有接口
BeanFactory ApplicationContext ,创建类实例的时间节点不一样?
xml 的 2种参数注入方式(set注入和 构造方法注入)
xml 向属实里面设置空值,特殊值,内部bean赋值,引用赋值,集合
spring xml p和 util 的namespan
FactoryBean 和 BeanFactory 区别,都是工厂类,前者是 spring的 bean 工厂,后者是spring 提供给我们实现工厂的接口
xml 通过 scope 可以设置 是单例还是多例(singleton,prototype),注解方式需要借助ObjectFactory 来得到多例
bena的生命周期 @PreDestroy,@PostConstruct ,@Bean(initMethod = "init", destroyMethod = "destroy") 在容器关闭的时候的顺序
BeanPostProcessor 里面 bean 的生命周期阶段监听函数
BeanPostProcessor 对所有 spring容器托管的bean都生效
@Resource ,@Autowired,@Qualifier ,Resource 可以指定 name ,Autowired 需要通过 Qualifier 指定名字,Resource 如果没有指定名字,那么变量名字优先,找不到会按照类型匹配,比Autowired 更加精确,所以有部分人推荐使用Resource
xml 方式 的 Autowire 支持 byType 和 byName 2种方式
xml 方式 通过 <context:property-placehoder location="文件.xml" >引入多个 xml 文件,神效时间是全程还是之前引入的才生效?
XMLApplicationContext 里面要使用注解需要 <context:component-scan base-package="">
xml 包扫描的 过滤器 使用自定义过滤器
spring 容器的生命周期接口函数 有哪些
spring纯注解方式使用的 AnnotationConfigApplicationContext 指定配置类来实现的
AOP 部分
spring AOP的 的 两种方式 ,动态代理(需要接口) 和 CGlib织入(修改源码)
JDK的 动态代理
AOP 的 5种切入类型
aspectj
https://blog.csdn.net/java_green_hand0909/article/details/90238242
xml 方式的 切面程序<aop:aspectj-autoproxy >
@Aspect 通过 @order 调整顺序
@EnableAspectjAutoProxy(proxyTargerClass=true)
能耍的时候就一定要耍,不能耍的时候一定要学。
--天道酬勤,贵在坚持posted on 2018-07-10 20:29 zhangyukun 阅读(142) 评论(0) 收藏 举报
浙公网安备 33010602011771号