企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
> **bean 从生到死** >--- 1. Spring 对bean进行实例化。 2. Spring将值和bean的引用注入到bean对应的属性上。 3. 如果bean实现了BeanNameAware接口,Spring将bean 的ID传递给setBeanName() 方法。 4. 如果bean 实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入。 5. 如果bean实现了ApplicationContextAware接口,Spring 将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来。 6. 如果bean实现了BeanPostProcessor接口,Spring将调用他们的postProcessBeforeInitialization方法。 7. 如果bean 实现了InitializingBean 接口,Spring将调用他们的afterPropertiesSet()类似的,如果bean 使用init-method声明了初始化方法,该方法也会被调用。 8. 如果bean 实现了BeanPostProcessor接口,Spring将调用他们的postProcessAfterInitialization()方法 9. 此时,bean已经就绪,可以被应用程序使用了,他们将一直驻留在应用程序上下文中,直到该应用上下文被销毁。 10. 如果bean实现了DisposableBean 接口,Spring将调用destory()接口方法,同样,如果bean使用destory-method声明了销毁方法,该方法也会被调用。 ---- >**BeanFactory和FactoryBean** >--- 1. BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。 ~~~ Resource resource = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource); ClassPathResource resource = new ClassPathResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource); ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"}); BeanFactory factory = (BeanFactory) context; ~~~ 2. 以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T >接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。例如自己实现一个FactoryBean,功能:用来代理一个对象,对该对象的所有方法做一个拦截,在调用前后都输出一行LOG,模仿ProxyFactoryBean的功能。 ~~~ /** * my factory bean<p> * 代理一个类,拦截该类的所有方法,在方法的调用前后进行日志的输出 * @author daniel.zhao * */ public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean { private static final Logger logger = LoggerFactory.getLogger(MyFactoryBean.class); private String interfaceName; private Object target; private Object proxyObj; @Override public void destroy() throws Exception { logger.debug("destroy......"); } @Override public void afterPropertiesSet() throws Exception { proxyObj = Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[] { Class.forName(interfaceName) }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { logger.debug("invoke method......" + method.getName()); logger.debug("invoke method before......" + System.currentTimeMillis()); Object result = method.invoke(target, args); logger.debug("invoke method after......" + System.currentTimeMillis()); return result; } }); logger.debug("afterPropertiesSet......"); } @Override public Object getObject() throws Exception { logger.debug("getObject......"); return proxyObj; } @Override public Class<?> getObjectType() { return proxyObj == null ? Object.class : proxyObj.getClass(); } @Override public boolean isSingleton() { return true; } public String getInterfaceName() { return interfaceName; } public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object getProxyObj() { return proxyObj; } public void setProxyObj(Object proxyObj) { this.proxyObj = proxyObj; } } ~~~ --- ~~~ <bean id="fbHelloWorldService" class="com.ebao.xxx.MyFactoryBean"> <propertyname="interfaceName" value="com.ebao.xxx.HelloWorldService" /> <property name="target" ref="helloWorldService" /> </bean> ~~~ --- ~~~ @RunWith(JUnit4ClassRunner.class) @ContextConfiguration(classes = { MyFactoryBeanConfig.class }) public class MyFactoryBeanTest { @Autowired private ApplicationContext context; /** * 测试验证FactoryBean原理,代理一个servcie在调用其方法的前后,打印日志亦可作其他处理 * 从ApplicationContext中获取自定义的FactoryBean * context.getBean(String beanName) ---> 最终获取到的Object是FactoryBean.getObejct(), * 使用Proxy.newInstance生成service的代理类 */ @Test public void testFactoryBean() { HelloWorldService helloWorldService = (HelloWorldService) context.getBean("fbHelloWorldService"); helloWorldService.getBeanName(); helloWorldService.sayHello(); } } ~~~ --- >**SpringIOC 的理解,其初始化过程?** > --- IoC容器是什么? IoC文英全称Inversion of Control,即控制反转,我么可以这么理解IoC容器:   “把某些业务对象的的控制权交给一个平台或者框架来同一管理,这个同一管理的平台可以称为IoC容器。” 我们刚开始学习spring的时候会经常看到的类似下面的这代码: ~~~ ApplicationContext appContext = new ClassPathXmlApplicationContext("cjj/models/beans.xml"); Person p = (Person)appContext.getBean("person"); ~~~ 上面代码中,在创建ApplicationContext实例对象过程中会创建一个spring容器,该容器会读取配置文件"cjj/models/beans.xml",并统一管理由该文件中定义好的所有bean实例对象,如果要获取某个bean实例,使用getBean方法就行了。例如我们只需要将Person提前配置在beans.xml文件中(可以理解为注入),之后我们可以不需使用new Person()的方式创建实例,而是通过容器来获取Person实例,这就相当于将Person的控制权交由spring容器了,差不多这就是控制反转的概念。 那在创建IoC容器时经历了哪些呢?为此,先来了解下Spring中IoC容器分类,继而根据一个具体的容器来讲解IoC容器初始化的过程。 Spring中有两个主要的容器系列: 1. 实现BeanFactory接口的简单容器; 2. 实现ApplicationContext接口的高级容器。 ApplicationContext比较复杂,它不但继承了BeanFactory的大部分属性,还继承其它可扩展接口,扩展的了许多高级的属性,其接口定义如下: ~~~ public interface ApplicationContext extends EnvironmentCapable,                   ListableBeanFactory, //继承于BeanFactory                   HierarchicalBeanFactory,//继承于BeanFactory                   MessageSource, //                   ApplicationEventPublisher,//                   ResourcePatternResolver //继承ResourceLoader,用于获取resource对象 ~~~ 在BeanFactory子类中有一个DefaultListableBeanFactory类,它包含了基本Spirng IoC容器所具有的重要功能,开发时不论是使用BeanFactory系列还是ApplicationContext系列来创建容器基本都会使用到DefaultListableBeanFactory类,可以这么说,在spring中实际上把它当成默认的IoC容器来使用。下文在源码实例分析时你将会看到这个类。 关于Spirng IoC容器的初始化过程在《Spirng技术内幕:深入解析Spring架构与设计原理》一书中有明确的指出,IoC容器的初始化过程可以分为三步: * Resource定位(Bean的定义文件定位)--定位并获取资源文件 * 将Resource定位好的资源载入到BeanDefinition --解析资源文件 * 将BeanDefiniton注册到容器中 --注册 --- >**BeanFactory和 ApplicationContext?** >--- 在Srping Ioc容器中,有BeanFactory和ApplicationContext两个系列,分别是: * 实现BeanFactory接口的简单容器,具备最基本功能。 * 实现ApplicationContext接口的复杂容器,具备高级功能。 *** 1. BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。 相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。BeanFacotry延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用 ApplicationContext。应用上下文则会在上下文启动后预载入所有的单实例Bean。通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。 2. BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。(Applicationcontext比 beanFactory 加入了一些更好使用的功能。而且 beanFactory 的许多功能需要通过编程实现而 Applicationcontext 可以通过配置实现。比如后处理 bean , Applicationcontext 直接配置在配置文件即可而 beanFactory 这要在代码中显示的写出来才可以被容器识别。 ) 3. beanFactory主要是面对与 spring 框架的基础设施,面对 spring 自己。而 Applicationcontex 主要面对与 spring 使用的开发者。基本都会使用 Applicationcontex 并非 beanFactory 。 --- >**Spring AOP 的实现** >--- 先了解AOP的相关术语: 1. 通知(Advice): 通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。 2. 连接点(Joinpoint): 程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。 3. 切入点(Pointcut) 通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正则表达式来指定 4. 切面(Aspect) 通知和切入点共同组成了切面:时间、地点和要发生的“故事” 5. 引入(Introduction) 引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能) 6. 目标(Target) 即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事) 7. 代理(proxy) 应用通知的对象,详细内容参见设计模式里面的代理模式 8. 织入(Weaving) 把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机: * 编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器 * 类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码 * 运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术 Spring提供了4种实现AOP的方式: 1. 经典的基于代理的AOP 2. @AspectJ注解驱动的切面 3. 纯POJO切面 4. 注入式AspectJ切面 --- > >---