当前位置: 首页 > news >正文

asp.net 微网站开发教程商城网站大概多少钱

asp.net 微网站开发教程,商城网站大概多少钱,织梦通用企业网站模板,如何用wix做网站Spring 篇 Spring框架中的单例bean是线程安全的吗#xff1f; 不是线程安全的 Spring bean并没有可变的状态(比如Service类和DAO类)#xff0c;所以在某种程度上说Spring的单例bean是线程安全的。 Spring框架中有一个Scope注解#xff0c;默认的值就是singleton#xff0…Spring 篇 Spring框架中的单例bean是线程安全的吗 不是线程安全的 Spring bean并没有可变的状态(比如Service类和DAO类)所以在某种程度上说Spring的单例bean是线程安全的。 Spring框架中有一个Scope注解默认的值就是singleton单例的。因为一般在spring的bean的中都是注入无状态的对象没有线程安全问题如果在bean中定义了可修改的成员变量是要考虑线程安全问题的可以使用多例或者加锁来解决 当多用户同时请求一个服务时容器会给每一个请求分配一个线程这是多个线程会并发执行该请求对应的业务逻辑(成员方法)如果该处理逻辑中有对该单列状态的修改(体现为该单例的成员属性) 则必须考虑线程同步问题。 如何处理 Spring 单例有状态的Bean 的线程安全问题 将 Bean 的作用域由 “singleton” 单例 改为 “prototype” 多例。在 Bean 对象中避免定义可变的成员变量当然这样做不太现实就当我没说。在类中定义 ThreadLocal 的成员变量并将需要的可变成员变量保存在ThreadLocal 中ThreadLocal 本身就具备线程隔离的特性这就相当于为每个线程提供了一个独立的变量副本每个线程只需要操作自己的线程副本变量从而解决线程安全问题 Spring事务失效 非public方法 默认情况下只有public修饰的方法才能被Spring的事务管理器拦截非public方法会被忽略。 Transactional是基于动态代理实现的当创建bean实例时Spring框架会扫描带有Transactional注解的方法并通过AOP技术生成代理对象并对事务进行管理。动态代理只能代理public方法。 异常被捕获并处理了 如果在Transactional注解标记的方法中出现了异常但是该异常被捕获并处理了并没有抛出异常那么这个事务就会正常提交而不是回滚。 抛出检查异常 Spring 默认只会回滚非检查异常不指定rollbackFor参数的前提下 非检查异常在编译时不需要强制处理的异常。这些异常一般是由程序逻辑错误或者系统内部错误导致的 例如空指针异常NullPointerException、数组越界异常ArrayIndexOutOfBoundsException等 检查异常在编译时需要显式处理的异常。通常表示程序运行中可能出现的外部错误或不正常情况通常表示程序运行中可能出现的外部错误或不正常情况 常见的检查异常包括IOException、SQLException等。 解决办法 配置rollbackFor属性Transactional(rollbackForException.class) 没有开启事务注解支持 在Spring Boot项目中需要在配置类上添加 EnableTransactionManagement 注解来启用事务注解支持。 类内部调用Transactional标注的方法 Transactional的实现原理在于以该注解为切面坐标在扫描动态生成的代理类中以此坐标来在其前后分别设置事务开启和事务提交操作的增强那么这些的前提是在于你的操作环境是在于Spring动态代理生成的代理类中而不是this对应的本类 当一个Bean需要被注入其它Bean时Spring会创建一个代理对象来代替真正的Bean对象。这个代理对象会拦截目标Bean对象的方法调用并在方法调用前后进行一些操作比如实现事务管理、缓存处理等。这样通过代理对象的调用就可以实现一些横切关注点的统一处理。 解决方法 Bean的生命周期 Spring 生命周期全过程大致分为五个阶段 创建前准备阶段 Bean 在开始加载之前需要从上下文和相关配置中解析并查找 Bean 有关的扩展实现 创建实例阶段 这个阶段主要是通过反射来创建 Bean 的实例对象并且扫描和解析 Bean 声明的一些属性 依赖注入阶段 被实例化的 Bean 存在依赖其他 Bean 对象的情况则需要对这些依赖 bean 进行对象注入 同时在这个阶段会触发一些扩展的调用比如常见的扩展类BeanPostProcessors用来实现 bean 初始化前后的扩展回调、InitializingBean这个类有一个 afterPropertiesSet()这个在工作中也比较常见、BeanFactoryAware 等等。 PostConstruct注解用于标记一个方法该方法在类实例化后被调用在依赖注入完成之后执行。它的作用是在对象创建后执行一些初始化操作——[解决静态方法中调用注入Bean对象] 容器缓存阶段 容器缓存阶段主要是把 bean 保存到容器以及 Spring 的缓存中到了这个阶段Bean就可以被开发者使用了。BeanPostProcessors 方法中的后置处理器方法如postProcessAfterInitialization也会在这个阶段触发。 销毁实例阶段 当 Spring 应用上下文关闭时该上下文中的所有 bean 都会被销毁。如果存在 Bean 实现了 DisposableBean 接口或者配置了destory-method属性会在这个阶段被调用。 通过BeanDefinition获取bean的定义信息调用构造函数实例化beanbean的依赖注入处理Aware接口(BeanNameAware、BeanFactoryAware、ApplicationContextAware)Bean的后置处理器BeanPostProcessor-前置初始化方法(InitializingBean、init-method)Bean的后置处理器BeanPostProcessor-后置销毁bean Spring中的Bean都是代理Bean 并非所有的Bean都会被声明为需要代理只有被特定的AOP切面所切入的Bean才会生成AOP代理对象。其他非代理的Bean仍然会作为原始对象被实例化和注入。因此虽然Spring加载的对象确实大部分是通过代理方式生成的AOP代理对象但仍然存在一部分对象是原始对象。 例子说明 假设我们有两个Bean分别是UserService和OrderService。其中UserService需要被AOP代理以实现事务管理的功能而OrderService不需要被代理。 在Spring的配置中我们可以通过对UserService添加Transactional注解来标明该Bean需要生成AOP代理对象。而对于OrderService则不需要做任何特殊的标记它会作为原始对象被实例化和注入。 Service public class UserService { ​Autowiredprivate UserDao userDao; ​Transactionalpublic void addUser(User user) {userDao.addUser(user);} ​// other methods... } ​ Service public class OrderService { ​Autowiredprivate OrderDao orderDao; ​public void addOrder(Order order) {orderDao.addOrder(order);} ​// other methods... }在上述代码中UserService被标记为Service注解并且其中的addUser方法被标记为Transactional注解表示该方法需要被事务管理。因此Spring会为UserService生成一个AOP代理对象并在Bean初始化时将该代理对象注入到其他需要UserService依赖的Bean中。 而OrderService则没有任何特殊的注解标记因此Spring会将其作为原始对象进行实例化和注入。 Bean循环依赖 / 三级缓存 三种形态 互相依赖A 依赖 BB 又依赖 A它们之间形成了循环依赖。三者间依赖A 依赖 BB 依赖 CC 又依赖 A形成了循环依赖。是自我依赖A 依赖 A 形成了循环依赖。 三级缓存 一级缓存 缓存完全实例化且属性赋值完成的 Bean 可以直接使用 限制bean在beanFactory中只存一份即实现singleton scope单靠它解决不了循环依赖 二级缓存 缓存早期的bean对象生命周期还没走完只实例加载了没有依赖注入懒加载机制 三级缓存 缓存的是ObjectFactory存储的是代理的Bean的工厂对象而不是代理的Bean本身。 三级缓存value存的不是bean是ObjectFactory用来生成早期Bean对象并放入二级缓存中 执行流程 当我们调用getBean( )方法的时候先去一级缓存找目标Bean找不到就去二级缓存找如果二级缓存也没有意味着这Bean还没有被实例化Spring就会去实例化该目标Bean将其丢到二级缓存中然后对该Bean标记是否具有循环依赖如果没有循环依赖则不动它如果具有循环依赖则等待下一次轮询进行再赋值也就是解析Autowired 注解。等Autowired 注解赋值完成后会将目标 Bean 存入到一级缓存。 可以说Spring的Bean是一种懒加载的机制。在Spring容器初始化时并不会立即对所有的Bean进行属性的赋值而是在需要使用Bean时才会进行属性的填充和赋值。 当调用getBean()方法获取Bean实例时如果Bean已经在一级缓存中则直接返回已经完成属性填充的Bean对象如果Bean在二级缓存中则检查是否存在循环依赖如果不存在循环依赖则创建一个代理对象返回等待后续的属性填充如果Bean还未实例化则会进行实例化并放入二级缓存中等待后续的属性填充和解析Autowired注解的过程。 具备一二级为什么需要第三级的缓存 循环依赖的可能是 AOP 代理之后的对象而不是原始对象 如果不存在代理对象二级缓存就可以解决循环依赖性的问题但是当存在代理对象的时候二级缓存则无法完全解决循环依赖需要引入三级缓存 当使用 CGLIB 代理时代理对象无法被缓存。这就意味着在二级缓存中我们无法获取到代理对象。如果不存在代理对象的时候可以借助早期Bean来实现提前曝光但是如果该循环的对象被AOP这些修饰了它被注入到其他类中的实例一定得是一个代理类实例 如果需要被代理的类出现了循环依赖的情况Spring必须在创建Bean时就创建代理对象才能保证循环依赖的解决。这就违背了Spring的设计原则。因为在循环依赖的情况下如果Bean之间的依赖没有完成Bean就无法完成创建。如果此时再去为它们创建代理可能会出现问题。 因此为了解决循环依赖的问题使用第三级缓存是比较合适的做法如果发现循环对象需要被代理的就将该对象通过JDK代理 / Cglib代理调用FactoryBean的getObject( )创建一个代理工厂对象并将其该类的 BeanDefinition 信息一起存储到三级缓存中在循环依赖并需要使用代理对象的情况下就可以从三级缓存中获取所有必要的信息来创建代理对象来进行一个类似于曝光的操作。让该需要被代理的类所依赖的类创建出来丢到一级缓存中这个半成品代理对象再从一级缓存中拿到其依赖的类变得完整最后将这代理对象放到一级缓存中。删除二级缓存的半成品代理对象 虽然它一样是基于早期的不完整的 Bean 实例来创建的但是Spring出手维护了下所以这个代理对象是可以被拿来当作曝光用的 具备一三级为什么需要第二级的缓存 要知道三级缓存中存储的都是代理对象的工厂对象每次通过这个工厂对象的getObject方法获取到的代理对象都是不一样的噢也就是不是单例的啦。 不能解决循环依赖的情况 多例 Bean 通过 setter 注入的情况不能解决循环依赖问题 这是因为多例下你通过曝光得到了一个对象让自己完整了但是那个对象想来引用你哦吼找不到你在哪了解决办法 加上延迟加载注解Lazy其效果是什么时候需要该对象才进行Bean对象创建 构造器注入的 Bean 的情况不能解决循环依赖问题 本质上是因为构造器注入需要将对象的实例化和依赖注入两个步骤绑定为一个原子步骤这样子就不能通过曝光来实现破局 解决办法 加上延迟加载注解Lazy其效果是什么时候需要该对象才进行Bean对象创建 Spring 事务传播行为 Spring 为了解决这个问题定义了 7 种事务传播行为。 REQUIRED默认的 Spring 事物传播级别如果当前存在事务则加入这个事务如果不存在事务就新建一个事务。REQUIRE_NEW不管是否存在事务都会新开一个事务新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交。NESTED如果当前存在事务则嵌套在当前事务中执行。如果当前没有事务则新建一个事务类似于 REQUIRE_NEW。SUPPORTS表示支持当前事务如果当前不存在事务以非事务的方式执行。NOT_SUPPORTED表示以非事务的方式来运行如果当前存在事务则把当前事务挂起。MANDATORY强制事务执行若当前不存在事务则抛出异常.NEVER以非事务的方式执行如果当前存在事务则抛出异常。 主要从你和我双方有没有的角度去回答 Bean作用域 理论上来说常规的生命周期只有两种 singleton 也就是单例意味着在整个 Spring 容器中只会存在一个 Bean 实例。prototype翻译成原型意味着每次从 IOC 容器去获取指定 Bean 的时候都会返回一个新的实例对象。 但是在基于 Spring 框架下的 Web 应用里面增加了一个会话纬度来控制 Bean 的生命周期主要有三个选择 request 针对每一次 http 请求都会创建一个新的 Beansession以 sesssion 会话为纬度同一个 session 共享同一个 Bean 实例不同的 session 产生不同的 Bean 实例globalSession针对全局 session 纬度共享同一个 Bean 实例 在Spring 5.0前的默认方案是懒汉式的单例在首次被调用时才进行实例化并且只实例化一次后续的调用都返回同一个实例。从 Spring 5.0 开始Spring 的单例 bean 默认采用的是饿汉式的实现即在容器启动时就实例化并初始化单例 bean而不是延迟加载 /*Spring5.0前的懒汉式实现主要采用的是双重检查锁定的方案 */ public class SingletonBean {// 声明静态的 SingletonBean 实例private static volatile SingletonBean instance;// 私有化构造函数防止外部实例化private SingletonBean() {}// 获取 SingletonBean 实例的静态方法public static SingletonBean getInstance() {// 双重检查锁定确保只有实例不存在时才进行实例化if (instance null) {synchronized (SingletonBean.class) {if (instance null) {instance new SingletonBean();}}}return instance;}// 随便一个方法来确认单例成功创建了public void doSomething() {System.out.println(SingletonBean.doSomething() method is called.);} }/*在 Spring 5.0 或更新版本中可以通过 Configuration 注解配合 Bean 注解来实现饿汉式创建Bean */ Configuration public class SingletonBean {// 声明静态的 SingletonBean 实例private static SingletonBean instance new SingletonBean();// 私有化构造函数防止外部实例化private SingletonBean() {}// 提供静态方法获取 SingletonBean 实例public static SingletonBean getInstance() {return instance;}// 随便一个方法来确认单例成功创建了public void doSomething() {System.out.println(SingletonBean.doSomething() method is called.);}Beanpublic SingletonBean createSingletonBean() {return getInstance();} }如何将Bean纳入Spring的管理 使用 xml 的方式来声明 Bean 的定义Spring 容器在启动的时候会加载并解析这个 xml把 bean 装载到 IOC 容器中。使用CompontScan 注解来扫描声明了Controller、Service、 Repository、Component 注解的类。使用Configuration 注解声明配置类并使用Bean 注解实现 Bean 的定义使用Import 注解导入配置类或者普通的 Bean使用 FactoryBean 工厂 bean动态构建一个 Bean 实例Spring Cloud OpenFeign 里面的动态代理实例就是使用 FactoryBean 来实现的。 BeanFactory和FactoryBean的区别 在Spring中最核心的就是Ioc容器它保存了所有需要对外提供的Bean的实例。Spring对外暴露的ApplicationContext作为IoC容器最重要的接口它也实现了 BeanFactory 接口。 BeanFactory 用于访问Spring bean容器的根接口。这是Spring bean容器的基本客户端视图。原来是获取Spring Bean的接口也就是IoC容器。我们更常用的ApplicationContext就是一个BeanFactory。我们通过bean的名称或者类型都可以从BeanFactory来获取bean FactoryBean 是一个特殊的Bean这个Bean可以返回创建Bean的工厂。 当我们想要从BeanFactory中获取创建Bean的Factory时可以在beanName前面加上 符号就可以获得Bean对应的Factory。 FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式。Bean的代理对象就是FactoryBean实现的 功能用途 BeanFactory提供了依赖注入和控制反转的功能不提供复杂的Bean初始化逻辑FactoryBean支持复杂的Bean初始化逻辑或延迟初始化eg数据库连接、Bean的AOP代理 返回值 BeanFactory返回的直接就是Bean对象本身。我们可以使用BeanFactory的getBean()方法通过传入FactoryBean的名称来获取FactoryBean生成的Bean对象。当传入的名称前面添加了符号时getBean()方法将返回FactoryBean本身。当你通过getBean方法获取一个普通的Bean实例时getBean方法内部会直接从IoC容器中获取Bean实例而不是走FactoryBean的getObject方法获取FactoryBean返回的是一个代理Bean或者包装Bean 总结 二者都是用来创建对象的 当使用BeanFactory的时候必须遵循完整的创建过程,这个过程是由Spring来管理控制的 而使用FactoryBean只需要调用getObject就可以返回具体的对象,整个对象的创建过程是由用户自己来控制的,更加灵活. BeanFactory和ApplicationContext有什么区别 BeanFactory和ApplicationContext是Spring的两大核心接口都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。 功能上的区别 BeanFactory是Spring里面最底层的接口包含了各种Bean的定义读取bean配置文档管理bean的加载、实例化控制bean的生命周期维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生除了提供BeanFactory所具有的功能外还提供了更完整的框架功能如继承MessageSource、支持国际化、统一的资源文件访问方式、同时加载多个配置文件等功能。 加载方式的区别。 BeanFactroy采用的是延迟加载形式来注入Bean的即只有在使用到某个Bean时(调用getBean())才对该Bean进行加载实例化。这样我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入BeanFacotry加载后直至第一次使用调用getBean方法才会抛出异常。而ApplicationContext是在容器启动时一次性创建了所有的Bean。这样在容器启动时我们就可以发现Spring中存在的配置错误这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单例Bean那么在需要的时候不需要等待创建bean因为它们已经创建好了。 相对于基本的BeanFactoryApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时程序启动较慢。 创建方式的区别。 BeanFactory通常以编程的方式被创建ApplicationContext还能以声明的方式创建如使用ContextLoader。 注册方式的区别。 BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用但两者之间的区别是BeanFactory需要手动注册而ApplicationContext则是自动注册。 Spring IoC 的工作流程 IOC 的全称是 Inversion Of Control, 也就是控制反转它的核心思想是把对象的管理权限交给容器。 应用程序如果需要使用到某个对象实例直接从 IOC 容器中去获取就行不需要在一个类中去实例化另一个类对象这样设计的好处是降低了程序里面对象与对象之间的耦合性。 Spring IOC 的工作流程大致可以分为两个阶段。 IOC 容器的初始化 首先一个IoC容器应创建一个工厂DefaultListableBeanFactory可以使我们读取的资源文件可以存放。 然后根据程序中定义的 XML 或者注解等 Bean 的声明方式通过解析和加载后生成 BeanDefinition然后把 BeanDefinition 注册到 IOC容器 注意这里不是直接就是将该Bean的实例注册加载到容器中而是Bean的BeanDefinition 最后把这个 BeanDefinition 保存到一个 Map 集合里面从而完成了 IOC 的初始化 BeanDefinition 是 Spring 容器中用来描述和定义一个 Bean 的元数据对象。它包含了关于 Bean 的一些重要信息如 Bean 的类名、作用域、依赖关系、初始化方法、销毁方法等等。BeanDefinition 本质上是一个配置对象用于告诉 Spring 容器如何创建和管理这个 Bean。 总结BeanDefinition 描述了一个 Bean 应该具有的属性和行为而 Bean 实例则是这个描述的具体实现。 对于设置lazy-init 属性为false的Bean在容器初始化后就会进行实例化存储到Bean容器中 调用了getBean()方法Bean 初始化及依赖注入 然后进入到第二个阶段这个阶段会做两个事情 通过反射针对没有设置 lazy-init 属性 默认为true懒加载 的单例 bean 进行初始化。执行实例化之前的一些准备初始化啊、事件处理器、注册组件等 在 Spring 5.0后默认情况下单例作用域的 Bean 是在容器启动时就会被实例化和初始化的。但是如果你将单例 Bean 的 lazy-init 属性设置为 true那么该 Bean 将会在第一次被使用时才会被实例化和初始化。 实例化Bean 检查和解析 Bean 之间的依赖关系完成 Bean 的依赖注入。 Autowired 和Resource的注入区别 Autowired Autowired 是 Spring 提供的一个注解默认是根据类型来实现Bean 的依赖注入 Autowired 注解里面有一个 required 属性默认值是 true表示强制要求 bean 实例的注入在应用启动的时候如果 IOC 容器里面不存在对应类型的 Bean就会报错。当然如果不希望自动注入可以把这个属性设置成 false 解决存在多个注入类型的实例 如果在 Spring IOC 容器里面存在多个相同类型的 Bean 实例。由于Autowired 注解是根据类型来注入 Bean 实例的所以 Spring 启动的时候会提示一个错误大概意思原本只能注入一个单实例 Bean但是在 IOC 容器里面却发现有多个导致注入失败。 解决方法如下 Primary 表示主要的 bean当存在多个相同类型的 Bean 的时候优先使用声明了Primary 的 Bean Qualifier 它可以根据 Bean 的名字找到需要装配的目标 Bean Autowired查找Bean的时间复杂度为O(n) Autowired注解是按照类型进行查找的如果有多个同类型的Bean那么还需要配合Qualifier注解来指定Bean的名称。当使用Autowired注解进行依赖注入时Spring需要遍历beanDefinitionMap中的所有Bean找出所有类型匹配的Bean然后再根据Qualifier指定的名称进行筛选。由于需要遍历所有的Bean所以Autowired查找Bean的时间复杂度是O(n)。 Resource Resource 是 JDK 提供的注解只是 Spring 在实现上提供了这个注解的功能支持。 Resource 可以支持ByName 和 ByType 两种注入方式具体采用哪个取决于属性 name 和 type 如果两个属性都没配置就先根据定义的属性名字去匹配如果没匹配成功再根据类型匹配。两个都没匹配到就报错 Resource查找Bean的时间复杂度为O(1) Resource注解是按照name属性进行查找的如果没有指定name属性那么默认是按照字段名进行查找。在Spring的DefaultListableBeanFactory类中有一个beanDefinitionMap成员变量这是一个HashMap用于存储所有的Bean定义信息。当使用Resource注解进行依赖注入时Spring会直接根据Bean的名称在beanDefinitionMap中进行查找。由于HashMap的查找时间复杂度是O(1)所以Resource查找Bean的时间复杂度也是O(1)。 二者对比 Resource性能比Autowire好很多尤其是在bean个数较多的场景下。简单的说Resource相当于O(1)Autowire相当于O(n)Autowired 可以作用在Setter、构造器方法Resource 只可以使用在Setter方法上只能是单个单数的setter方法Spring 容器在启动时会扫描应用程序中已经定义的所有 Bean 定义或者根据一定的规则生成 Bean 定义。然后它会通过反射机制实例化每个 Bean并将其加入到容器中进行管理。二者底层都是通过反射机制去容器中找寻该Bean实例来进行注入如果被注解标记的类尚未被实例化为 BeanSpring 容器会在DefaultListableBeanFactory根据其类定义BeanDefinition 创建并实例化该 Bean 对象加入到Ioc容器中并返回该实例对象。 Spring依赖注入的方式 构造器注入setter注入接口注入变量注入 构造器注入 Component public class ExampleService {private Dependency dependency;public ExampleService(Dependency dependency) {this.dependency dependency;}// ... }在创建ExampleService时就会自动将一个Dependency实例注入到ExampleService中 优点 依赖注入中使用的依赖对象是可选的意思是注入的依赖对象是可以为NULL的允许在类构造完成后重新注入 缺点 注入对象不能被final修饰final 修饰的变量表示它的值一旦被初始化后就不能再被修改。而在变量注入的情况下Spring 框架在运行时会动态地将依赖注入到变量中这意味着变量的引用可能会在实例化后的任意时间点进行修改。 Setter方法注入 Component public class ExampleService {private Dependency dependency;public void setDependency(Dependency dependency) {this.dependency dependency;}// ... }优点 显式注明必须强制注入通过强制指明依赖注入来保证这个类的运行防止发生NullPointerException;注入的对象可以使用final修饰;可以避免循环依赖问题如果存在循环依赖的话Spring在项目启动的时候就会报错 缺点 当你有十几个甚至更多对象需要注入时构造函数的代码臃肿看起来不太舒服; 接口注入变量注入 这种方式要求目标Bean实现特定的接口并通过接口方法来设置依赖项。 public interface Dependency {void doSomething(); }Component public class ExampleDependency implements Dependency {Overridepublic void doSomething() {System.out.println(Doing something...);} }Component public class ExampleService {private Dependency dependency;Autowiredpublic ExampleService(Dependency dependency) {this.dependency dependency;}public void performAction() {// 使用依赖接口的方法dependency.doSomething();} }ExampleDependency实现了Dependency接口并被标记为Component成为一个由Spring管理的Bean。在ExampleService中通过构造函数注入Dependency接口的实例。当调用performAction()方法时会使用注入进来的Dependency实例执行相应的操作 可能会导致循环依赖问题并且启动的时候不会报错只有在使用那个bean的时候才会报错变量不能被final修饰 Bean 的加载机制 加载Bean的配置信息1.XML模式 2. 注解扫描模式 3.Configuration配置类的Bean配置模式Spring 解析这些声明好的配置内容将这些配置内容都转化为 BeanDefinition 对象BeanDefinition 中几乎保存了配置文件中声明的所有内容将 BeanDefinition 存到一个叫做 beanDefinitionMap 中。以 beanName 作为 Key以 BeanDefinition 对象作为 Value。Spring 容器根据 beanName 找到对应的 BeanDefinition再去选择具体的创建策略 具体什么创建策略得看你声明的这个Bean的作用域设置的是什么默认是采用单例模式的创建策略当你通过getBean方法获取一个普通的Bean实例时getBean方法内部会直接从IoC容器中获取Bean实例而不是走FactoryBean的getObject方法获取如果获取的是一个FactoryBean的Bean则会调用FactoryBean的getObject方法来获取到该代理 or 自定义加工后的Bean实例 Spring AOP 原理流程 创建代理对象阶段 在 Spring 中创建 Bean 实例都是从 getBean()方法开始的在实例创建之后Spring 容器将根据 AOP 的配置去匹配目标类的类名看目标类的类名是否满足切面规则。如果满足满足切面规则就会调用 ProxyFactory 创建代理 Bean并缓存到 IoC 容器中。 根据目标对象的自动选择不同的代理策略 JDK动态代理 / Cglib动态代理 如果目标类实现了接口Spring会默认选择 JDK Proxy如果目标类没有实现接口Spring 会默认选择 Cglib Proxy当然我们也可以通过配置强制使用 Cglib Proxy 拦截目标对象阶段 当用户调用目标对象的某个方法时将会被一个叫做AopProxy 的对象拦截然后按顺序执行符合所有 AOP 拦截规则的拦截器链。 调用代理对象阶段 Spring AOP 拦截器链中的每个元素被命名为 MethodInterceptor其实就是切面配置中的 Advice 通知。这个回调通知可以简单地理解为是新生成的代理 Bean 中的方法。也就是我们常说的被织入的代码片段这些被织入的代码片段会在这个阶段执行 调用目标对象阶段 MethodInterceptor 接口也有一个 invoke()方法在 MethodInterceptor 的 invoke()方法中会触发对目标对象方法的调用也就是反射调用目标对象的方法。 动态代理的本质 Cglib 动态代理底层实现 JDK动态代理虽然简单易用但是其有一个致命缺陷是只能对接口进行代理。如果要代理的类为一个普通类、没有接口那么Java动态代理就没法使用了。 Cglib的工作原理主要分为两个步骤 生成代理类Cglib通过读取被代理类的字节码借助 ASM库 来修改字节码生成一个新的类作为代理类。代理类是被代理类的子类并且会重写被代理类中的非final方法将代理逻辑插入到这些方法中。这些重写方法会在调用时首先执行代理逻辑然后再调用原始的被代理类方法。创建代理对象一旦生成了代理类的字节码就可以使用Java的反射机制实例化代理对象。Cglib通过创建代理对象的过程来连接代理类和被代理对象。在代理对象进行方法调用时实际上是通过调用代理类中重写的方法从而触发代理逻辑的执行。 CGLIB缺点 对于final方法无法进行代理。由于Cglib是通过修改字节码来实现动态代理的所以生成代理类的过程需要消耗一定的时间和资源。 Spring通知有哪些类型 前置通知Before在目标方法被调用之前调用通知功能后置通知After在目标方法完成之后调用通知此时不会关心方法的输出是什么返回通知After-returning 在目标方法成功执行之后调用通知异常通知After-throwing在目标方法抛出异常后调用通知环绕通知Around通知包裹了被通知的方法在被通知的方法调用之前和调用之后执行自定义的逻辑。 Spring 用到了哪些设计模式 单例模式: 在Spring中定义的bean默认是单例模式。 工厂模式Spring使用工厂模式通过BeanFactory、ApplicationContext创建Bean对象。 代理模式Spring AOP功能的实现是通过代理模式中的动态代理实现的。 策略模式Spring中资源访问接口Resource的设计是一种典型的策略模式。Resource接口是所有资源访问类所实现的接口Resource 接口就代表资源访问策略但具体采用哪种策略实现Resource 接口并不理会。客户端程序只和 Resource 接口耦合并不知道底层采用何种资源访问策略这样客户端程序可以在不同的资源访问策略之间自由切换。 适配器模式Spring AOP的增强或通知使用到了适配器模式。 环绕通知是最强大的一种通知类型它同时包含了前置通知和后置通知的功能并且可以完全控制方法的执行。 在实现环绕通知时需要使用到适配器模式。具体来说需要创建一个继承自 Spring 的 MethodInterceptor 接口的类该类中实现 invoke 方法该方法中包含了环绕通知的实现代码。 为了将 MethodInterceptor 接口的类与目标对象绑定起来在 Spring AOP 中使用了适配器模式具体来说适配器模式将 MethodInterceptor 接口的方法调用转换为了目标对象的方法调用从而实现了通知的功能。 装饰器模式Spring 中配置 DataSource 的时候DataSource 可能是不同的数据库和数据源项目需要连接多个数据库这种模式让我们可以根据客户需求切换不同的数据源。 模板模式Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类就是用到了模板模式。
http://www.zqtcl.cn/news/556156/

相关文章:

  • 注册top域名做公司网站男女做暖网站是什么
  • 郴州本地网站建设高端网站设计多少钱
  • 此网站域名即将过期广告制作属于什么行业
  • 牛牛襄阳网站建设wap网站asp源码
  • 信用网站建设招标书建网站需要什么手续
  • 重庆建网站方法网站开发和维护
  • 做网站需要什么人活动策划流程及细节
  • wordpress企业网站seo上海市
  • 北京建外贸网站公司网络域名是什么
  • 聚美优品网站建设方案上市公司的信息网站
  • 济南做网站比较好的公司知道吗为什么做美食视频网站
  • 药店网站源码宣传方式
  • word如何做网站链接淘宝客建站需要多少钱
  • 凡科网免费建站步骤及视频logo设计网页
  • 天梯网站建设软件开发公司职位
  • 建站公司外贸东方购物网上商城
  • 白银做网站企业免费网站模板
  • 网络公司给我们做的网站_但是我们不知道域名是否属于我们湖北正规网站建设质量保障
  • 本地网站asp iis团队展示网站
  • 企业网站管理系统cmswordpress知识管理系统
  • 创建一个网站需要怎么做销售平台公司
  • 网站域名实名认证吗做斗图的网站
  • 公司在兰州要做网站怎样选择做网站数据库表各字段详情
  • 营销型网站建设的要素搭建本地网站
  • 深圳网站建设V芯ee8888ewordpress瀑布流主 #65533;
  • 股票交易网站开发angular2做的网站有
  • 如何建立免费个人网站angularjs 网站开发
  • 湖南信息网官方网站安徽省房地产开发项目管理系统
  • a5建站无限动力网站
  • 南京网站建设王道下拉??怎么做免费网站推