Spring入门之IOC,AOP

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaoyaohuqijun/article/details/78119641

 

Spring是目前最流行的Java开发框架, Java 企业开发中的SSH或者SSM都与Spring有关。 Spring最根本的使命是简化Java开发。

基于这一使命,Spring有了以下4中关键策略:

1.      基于POJO 的轻量级和最小侵入式编程;

2.      通过依赖注入和面向接口编程实现松耦合;

3.      基于切面和惯例进行声明式编程;

4.      通过切面和模板减少样板式代码。

(PS.  Spring 实战,第4版)

 

 

这里简单的介绍下Spring最为核心的两个特性:IOC  和AOP

 

IOC(Inverse Of Control) 容器: 控制反转意思是应用程序不再负责维护对象(Java中主要是对象的创建,初始化),而将这部分工作交给IOC容器。  应用程序直接从IOC 容器中获取到所需要的对象,  只负责使用对象。

 

这是一种分工合作的思想,  将对象的维护和使用进行了分工,应用程序只负责使用对象。

 

DI(Dependency Injecttion)依赖注入在Spring 中一般作为IOC 容器的同义词(PS. Spring 实战第4版 一书就使用的是DI).   个人理解, DI 是通过IOC容器来实现的,  IOC 容器不仅可以生成Java 对象,  还可以组装Java 对象之间的依赖关系,  这正式IOC 强大的地方。  如果你有一个对象A ,  它持有对象B 的引用即A 依赖B,  那当你使用Spring IOC 容器获取A对象时,  A 引用的B 对象也已经被IOC 容器准备好并且赋值给A 中的属性。

 

Spring 的依赖注入一般有两种方式:

1.      设值注入

IOC 容器调用setter 方法将依赖注入到目标对象

2.      构造注入

依赖作为构造器的参数,通过构造函数注入到目标对象

 

Spring 中对象(Bean)的作用域:

1.      Singleton: 单例,一个bean容器中只存在一个, 默认行为;

2.      prototype:   每次向bean容器请求都会创建一个实例;

3.      request:  每次http请求都会创建一个实例,并且仅在当前request内有效,只web-aware Spring ApplicationContext的上下文中有

4.      session :  每个会话会创建一个实例,并且在当前会话内有效,只web-aware Spring ApplicationContext的上下文中有

5.      Global Session: 类似session,  只在portlet 环境中有效,  非portlet 环境中相当于session。只web-aware Spring ApplicationContext的上下文中有

 

Bean 的生命周期:

1.      定义

2.      初始化

实现InitializaingBean 接口或者配置init-method 方法

3.      使用

4.      销毁

实现DesposableBean 接口或者配置detroy-method 方法

 

 

 

 

Autowiring(自动装配):

1.      No, 默认行为

2.      byName

3.      byType

4.      Constructor

Spring 中可以开启自动装配功能, 这样不需要在bean的配置中显式的声明依赖对象,Spring 会自动进行依赖注入,通过配置的自动装配类型。

 

Aware 接口:

1.      ApplicationContextAware

2.      BeanNameAware

Aware 接口可以获取到Spring的相关资源(如果Context容器,BeanName)来进行相关的操作。

 

 

AOP(Aspect Oriented Programming,  面向切面编程),  通常用于分离业务逻辑和系统服务,实现松耦合

 

一般由预编译和动态代理两种实现方式,SpringAOP 是使用动态代理实现的。

 

Aspect(切面):一个关注点的模块化,会横切多个对象。

切面是一些系统级的服务,  每个业务模块都需要,  例如日志,性能统计,安全控制,事物处理等。

(PS. 事物, 一组操作要么一起成功要么一起失败)

 

PointCut(切点):  匹配连接点的断言

连接点就是切面和业务模块相连的地方, 即实际要触发执行切面动作的业务模块代码位置。

 

Advice(通知):切面在连接点要执行的动作,有以下几种类型:

1.      Before

2.      After returning

3.      After throwing

4.      After

5.      Around

 

 

 


实践问题:

1.      Spring 5 Scope 定义发生了变化

 


 

Spring 5 中Scope 有如下几种:

1.      Singleton

2.      Prototype

3.      Request

4.      Session

5.      Application

6.      WebSocket



2.      使用Spring bean 时候 Spring容器已经close,  bean 的destory-method 没有被调用,  配置destory 属性或者实现DisposableBean 接口都一样

 

 

Prototype下是没有destory 方式

Destroy method is not called forbeans of scope prototype. This is because the context doesn't keep track of theprototype scope objects (if it does, it will cause a memory leak as springdoesn't know when to dispose it).

https://stackoverflow.com/questions/16783552/destroy-method-is-not-working-in-spring-framework

 

3.       Bean 初始化和销毁两种方式优先级?

初始化:   afterPropertiesSet  ->  init-method

销毁:   destroy() ->   destroy-method

两种方式可以同时使用。

 

4.      Spring 作为Bean 容器有什么优点?

Spring 单独作为一个Bean 容器,  没有什么优点,  完全没必要。 使用Spring或者一个bean需要先在xml定义bean,  然后获得Spring 容器, 再从容器中取得bean.  过程比直接使用new 复杂多了。  如果单独作为一个bean 容器来使用完全是大材小用。 Spring 的优势是依赖注入,  当对象之间有复杂的依赖关系时,  使用Spring 容器的优势就体现出来了, 无论bean 依赖多严重,  还是可以直接从Spring 容器中获取需要的bean,  而且各种依赖关系Spring 都准备好了。

 

5.      使用Spring AOP 时,  死活不对(AOP 配置很简单), 一直提示:

Caused by: java.lang.NoClassDefFoundError:org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException

                atjava.lang.Class.getDeclaredConstructors0(Native Method)

                atjava.lang.Class.privateGetDeclaredConstructors(Class.java:2671)

                atjava.lang.Class.getConstructor0(Class.java:3075)

                atjava.lang.Class.getDeclaredConstructor(Class.java:2178)

                atorg.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:79)

                ...71 more

Caused by:java.lang.ClassNotFoundException:org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException

                atjava.net.URLClassLoader.findClass(URLClassLoader.java:381)

                atjava.lang.ClassLoader.loadClass(ClassLoader.java:424)

                atsun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)

                atjava.lang.ClassLoader.loadClass(ClassLoader.java:357)

                ...76 more

 

 

 

AOP 定义如下:

<?xml version="1.0"encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
      
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"
      
xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"
>

    <bean
id="User"class="User"scope="singleton" init-method="init"destroy-method="destory1">
       
<!--constructor-arg ref="IPhone"/ -->
       
<property name="phone"ref="IPhone"/>
    </bean>
    <bean
id="IPhone"class="Iphone"/>
    <bean
id="MyAspect"class="MyAspect"/>

    <
aop:config>
        <
aop:aspectid="Aspect"ref="MyAspect">
            <
aop:pointcutid="MyPointCut"
                         
expression="execution(**.recordMessage(..))"/>
            <
aop:before pointcut-ref="MyPointCut"
                        
method="monitorAspect"/>
        </
aop:aspect>
    </
aop:config>

   
<!--more bean definitions go here -->

</beans>

 

 

 

 

原因: 定义切点时,使用了AspectJ的切点表达式语言,  需要在依赖工程依赖中加入AspectJ 的依赖,  在POM 中添加AspectJ的依赖后问题解决:

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.11</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.11</version>
</dependency>

 

 



1.      装配Bean

 

Spring 装配Bean的方式:

1.      在XML 中进行显示配置

2.      在Java 中进行显示配置(注解)

3.      隐式的bean 发现机制和自动装配

 

Spring in Action 一书推荐优先使用组件扫描和自动装配,  其次是Java 配置,  再是XML 配置。

 

Spring Java 配置方式装配Bean 的常用注解:

@Component :  表明该类会作为组件类,Spring 要为这个类创建bean; 可以带一个字符串参数,显示指定bean ID.

如果不明确设置beanid , Spring  会根据类名指定一个, 即将类名的第一个字母小写作为ID.

@Configuration : 表明这是一个Spring 配置类

@ComponentScan:   开启组件扫描,扫描所有用@Component标记的类,  默认扫描与配置类相同的包, 可以用basePackage或者basePackageClasses属性来指定扫描的路径

@Autowired :   Sping 自动装配,  可以用于构造器和属性的setter 方法上,  required 属性默认为true,  意味着Spring 在创建应用上下文时,  如果没有匹配的bean 会抛出异常;  该属性设置为false 时,  如果没有批评的bean ,  Spring 会让这个bean 处于未装配的状态,  需要谨慎使用。

 

自动组件扫描和自动装配有时行不通,  例如需要将第三方库中的组件装配到应用中,  这时需要显示的配置Bean.

@Bean,    在javaConfig中声明bean(类似在xml 中声明bean)

 

@Configuration
//@ComponentScan(basePackageClasses = {Sgtpeppers.class})
public class CDPlayerConfig {
    
    @Bean
    public CompactDisc sgtPeppers()
    {
        return new Sgtpeppers();
    }
    
    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc)
    {
        return new CDPlayer(compactDisc);
    }
}

 

@Bean 注解可以采用任何有必要的Java功能来产生bean,构造器和Setter方法是最常见的, 可能性仅仅受Java语言的限制。

 

 

XML配置提供的能力和JavaConfig 基本类似,  这里不展开了,  xml 中可以配置list,map,set 等类型,  参考Spring-util 命名空间中的元素:

http://www.cnblogs.com/shuqi/p/4595618.html

 

@Profile,   用于实现不同的环境不同的配置

@Conditional, 可以用到带有@Bean 注解的之上, 实现条件化Bean,  给定条件为true,  就会创建这个bean.


 

 

没有更多推荐了,返回首页