Spring IOC DI AOP 的简单理解及应用

Spring两大特性:IOC 和AOP。IOC 控制反转,AOP 面向切面编程

  spring 核心容器的主要组件时Bean工厂(BeanFactory) ,Bean 工厂使用控制反转模式来降低程序代码之间的耦合度,并提供了面向切面编程的实现。

  Spring 常用的注解

  1. @Controller :用于标注控制器成组件。
  2. @Service:用于标注业务成组件。
  3. @Component : 用于标注这是一个受spring 容器管理的组件,组件引用名称是类名, 第一个字母小写。也可以使用@Component("beanName")指定组件的名称
  4. @Reposirty:用于标注数据库访问组件,即DAO组件。
  5. @Bean:方法级别的注解,主要用于@Configuration 或@Component 注解的类里, @Bean 注解的方法会产生一个Bean对象,该对象由Spring管理并放在IOC容器中。引用名称是方法名, 也可以使用@Bean(name = "beanName")指定组件名称
  6. @Scope("prototype"):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。由于Spring默认是单例模式,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。
  7. @Autowired:默认按照类型进行自动装配,在容器查找匹配的bean, 当仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
  8. @Resource:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按照类型装配。

    能够明确该类时一个控制器类组件时,就用@Controller;

    能够明确该类是一个服务类组件时,就用@Service;

    能够明确该类是一个数据访问组件时,就用@Repository;

    不明确它的作用时,使用@Component;

  控制反转IOC

  创建对象的控制权反转到Spring框架上。

  通常,实例化一个对象时,都是使用类的构造方法来new一个对象,这个过程是由我们自己来控制的,而控制反转就是把new对象的操作交给Spring容器

  IOC的主要实现方式:依赖查找、依赖注入。依赖注入是一种更可取的方式。

  依赖查找,依赖注入的区别?

  依赖查找:主要是容器为组件提供一个回调接口和上下文环境。组件必须自己使用容器提供的API来查找资源和协作对象,控制反转仅体现在那些回调方法上,容器调用这些回调方法,应用代码获取到资源。

  依赖注入:组件不做定位查询,只提供标砖的JAVA方法让容器去决定依赖关系,容器全权负责组件的装配,把符合依赖关系的对象通过JAVA Bean 属性或构造方法传递给需要的对象。

    

  IOC容器:具有依赖注入功能的容器,可以创建对象的容器。IOC容器负责实例化、定位、配置应用程序中的对象并建立这些对象之间的依赖。

  依赖注入:由IOC容器动态地将某个对象所需要的外部资源(包括对象、资源、常量数据)注入到组件之中

  Spring依赖注入的方式主要有四个:基于注解注入、Set注入方式、构造器注入方式、静态工厂注入方式。推荐使用基于注解注入的方式,配置少,比较方便。

  @Autowired和@Resource的区别

  共同点: @Autowired和@Resource都是用来装配Bean的, 都可以写在字段、setter方法上。

  不同点:

  @Autowired默认按照类型进行自动装配,该注解属于Spring,.默认情况下要求依赖对象必须存在,如果允许为null,需要设置required属性为false。如果要使用名称进行装配,可以和@QualiFier 注解一起使用

  

@Autowired
@QualiFier("beanName")
private BeanNameService beanNameService;

  @Resource默认按照名称进行装配,该注解属于J2EE,名称可以通过name属性来指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行装配;如果注解写在setter方法上,默认取属性名进行装配。当找不到与名称匹配的Bean时,会按照类型进行装配,但是,name属性一旦指定,就只会按照名称进行装配。

@Resource(name="beanNameService")
private BeanNameService beanNameService;

  面向切面编程AOP

  AOP一般应用于:签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等。

  切面(Aspect):共有功能的实现。如日志切面、权限切面、验签切面等。在实际开发中通常是一个存放共有功能实现的标准Java类。当Java类使用了@Aspect注解修饰时,就能被AOP容器识别为切面。

  通知(Advice):切面的具体实现。就是要给目标对象织入的事情。以目标方法为参照点,根据放置的地方不同,可分为前置通知、后置通知、异常通知、最终通知、环绕通知。通常切面类中的一个方法,具体属于哪类通知,通过方法上的注解区分。

  连接点(JoinPoint):程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出等。Spring只支持方法级的连接点。一个类的所有方法前、后、抛出异常时等都是连接点。

  切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

  目标对象(Target):那些即将切入切面的对象,也就是那些被通知的对象。这些对象专注业务本身的逻辑,所有的共有功能等待AOP容器的切入。

  代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象本身业务逻辑加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。目标对象被织入共有功能后产生的对象。

  织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译时、类加载时、运行时。Spring是在运行时完成织入,运行时织入通过Java语言的反射机制与动态代理机制来动态实现。

  Pointcut用法

   

execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

  修饰符匹配 modifier-pattern? 例:public private

  返回值匹配 ret-type-pattern 可以用 * 表示任意返回值

  类路径匹配 declaring-type-pattern? 全路径的类名

  方法名匹配 name-pattern 可以指定方法名或者用 * 表示所有方法;set* 表示所有以set开头的方法

  参数匹配 (param-pattern) 可以指定具体的参数类型,多个参数用“,”分隔;可以用 * 表示匹配任意类型的参数;可以用 (..) 表示零个或多个任意参数

  异常类型匹配throws-pattern? 例:throws Exception

  其中后面跟着 ? 表示可选项

@Pointcut("execution(public * com.project.springbootdemo.controller.*.*(..))")
private void sign() {
 
}

  示例:

  

/**
SignAop类使用了@Aspect注解,则该类可以被AOP容器识别为切面。

*/

@Aspect
@Component
public class SignAop {
 
/**@Pointcut声明一个切入点,范围为controller包下所有的类的所有方法*/
    @Pointcut("execution(public * cn.wbnull.springbootdemo.controller.*.*(..))")
    private void signAop() {
 
    }
     //doBefore()方法使用@Before("signAop()")注解,表示前置通知(在某连接点之前执行的通知),但这个通知不能阻止连接点之前的执行流程,除非它抛出一个异常。
    @Before("signAop()")
    public void doBefore(JoinPoint joinPoint) throws Exception {
        //code
       }
 
//doAfterReturning()方法使用@AfterReturning(value = "signAop()", returning = "params")注解,表示后置通知(在某连接点正常完成后执行的通知),通常在一个匹配的方法返回的时候执行。
    @AfterReturning(value = "signAop()", returning = "params")
    public JSONObject doAfterReturning(JoinPoint joinPoint, JSONObject params) {
        //code
        }
}

//实际运行时,在进入controller包下所有方法前,都会进入doBefore()方法,在controller包下方法执行完成后,都会进入doAfterReturning()方法。

  

猜你喜欢

转载自www.cnblogs.com/shar-wang/p/11622843.html