Skip to content

Latest commit

 

History

History
299 lines (222 loc) · 11.5 KB

5.Spring-IOCAOP机制.md

File metadata and controls

299 lines (222 loc) · 11.5 KB

1.Spring

1.1 Spring IOC

@RestController
public class MyController {

    @Resource
    private MyService myService;

    public void doRequest(HttpServletRequest request) {
        // 做请求
        myService.doService(request);
    }
}

public interface MyService {

}

@Service
public class MyServiceImpl implements MyService {

}

Spring IOC

Spring容器初始化

spring ioc:在tomcat启动的时候先启动spring容器,根据xml配置,或者是你的注解,去实例化你的一些bean对象,然后根据xml配置或者,去对bean对象之间的引用关系,去进行依赖注入。

底层核心就是反射,他会通过反射的技术,直接根据你的类去构建对应的对象出来。spring ioc,系统的类与类之间彻底的解耦合。

1.2 Spring AOP机制

@Service
public class MyServiceA {
    public void doServiceA() {
        // 开启事物

        // insert
        // update
        // update
        // delete

        // 如果有任何一个语句失败了,回滚事物
        // 如果大家都成功了,提交事物
    }

}

@Service
public class MyServiceB {
    public void doServiceB() {
        // 开启事物

        // update
        // update
        // insert

        // 如果有任何一个语句失败了,回滚事物
        // 如果大家都成功了,提交事物
    }
}

Spring AOP,可以做一个切面。在类似于MyServicexxx这种类,在这些类的方法中,都去织入一些代码,在所有这些方法刚开始运行的时候,都先去开始一个事物,在所有方法运行完毕之后,去根据是否异常抛出来判断,如果抛出异常,就回滚事物,如果没有异常就提交事物。

Spring在运行的时候,使用动态代理技术。

public class ProxyMyServiceA {
    private MyServiceA myServiceA;

    public void doServiceA() {
        // 开启事物

        //直接取调用我一来的MyServiceA 对象方法
        myServiceA.doServiceA();

        // 根据他是否抛出来提交事物或者回滚事物
    }
}
/**
 * @author finen
 * 把这个类声明为一个切面:需要把该类放入到IOC容器中,在声明为一个切面
 * 可以使@Order注解指定切面优先级,优先级值越小优先级越高
 */
@Order(2)
@Aspect
@Component
public class LoggingAspect {

    /**
     * 定义一个方法:用于声明切入点表达式,一般地,该方法中不需要切入其他的的代码
     * 使用@Pointcut来声明切入点表达式
     * 后面的其他通知直接使用方法名引用当前切入点表达式
     */
    @Pointcut("execution(public int top.finen.spring.aop.impl.ArithmeticCalculator.*(int, int))")
    public void declareJoinPointExpression() {}

    /**
     * 声明该方法是一个前置通知:在目标方法之前执行
     * 在声明能获取到执行的参数
     * @param joinPoint
     */
    @Before("declareJoinPointExpression()")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " begins with:" + args);
    }

    /**
     * 后置通知:在目标方法执行后(无论是否发生异常),执行的通知
     * 在后置通知中还不能访问目标方法执行的结果。
     * @param joinPoint
     */
    @After("declareJoinPointExpression()")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " end");

    }

    /**
     * 在方法结束受执行代码的之后返回的通知
     * 返回通知是可以访问到方法的返回值的
     * @param joinPoint
     */
    @AfterReturning(value = "declareJoinPointExpression()",
            returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " end with: " + result);

    }

    /**
     * 在方法出现异常时,会执行的代码
     * 可以访问到异常对象,且可以指定出现特定异常时在执行通知代码。
     * @param joinPoint
     * @param exception
     */
    @AfterThrowing(value = "declareJoinPointExpression()",
            throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Exception exception) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " throwing with: " + exception);
    }

    /**
     * 环绕通知需要携带ProceedingJoinPoint类型的参数
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
     * 环绕通知必须有返回值,且返回值为目标方法的返回值
     * @param proceedingJoinPoint
     */
    @Around("declareJoinPointExpression()")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {

        Object result = null;
        String methodName = proceedingJoinPoint.getSignature().getName();

        //执行目标方法
        try {
            //前置通知
            System.out.println("The method " + methodName + " begins with:" + Arrays.asList(proceedingJoinPoint.getArgs()));
            result = proceedingJoinPoint.proceed();
            //返回通知
            System.out.println("The method " + methodName + " end with:" + result);
        } catch (Throwable throwable) {
            //异常通知
            System.out.println("The method " + methodName + " throwing with: " + throwable);
            throwable.printStackTrace();
        }
        //后置通知
        System.out.println("The method " + methodName + " end");
        return result;
    }
}

1.3 cglib动态代理和jdk动态代理的区别

就是动态的创建一个代理类出来,创建这个代理类的实例对象,在这个里面引用你真正自己写的类,所有方法的调用,都是先走代理类的对象,他负责做一些代码上的增强,再去调用你写的那个类。

如果你的类是实现了某个接口的,spring aop会使用jdk动态代理,生成一个跟你实现同样接口的一个代理类,构造一个实例对象出来,jdk动态代理是在你的类有接口的情况下生成的。

很多时候,某各类可能没有实现接口,spring aop会改用cglib来生成动态代理,他是生成你的类的一个子类,他可以动态生成字节码,覆盖你的一些方法,再发方法里加入增强的代码。

1.4 spring中的bean是线程安全的?

Spring容器中的bean可以分为5个范围:

  • singleton:默认,每个容器只有一个bean实例
  • prototype:为每个bean请求提供一个实例
  • request:为每个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
  • session;与request范围类似,确保每个session有一个bean的实例,在session过期后,bean会随之失效。
  • global-session:
@RestController
public class MyController {

    @Resource
    private MyService myService;

    public void doRequest(HttpServletRequest request) {
        // 做请求
        myService.doService(request);
    }
}

public interface MyService {

}

@Service
public class MyServiceImpl implements MyService {
    public void doService() {
        // 访问数据库
    }

}

不可能线程安全的,每一次请求调用都会到一个bean中。通常在一些bean中很少会有实例变量的。通常都是访问数据库的。

Spring Bean

Spring Bean-1

1.5 Spring的事物实现原理,对事物的理解

事物实现原理,事物的传播机制。如果你加了一个@Transactional注解,此时spring就会使用AOP思想,对你的这个方法在执行之前,先去开启事物,在你的任务执行结束,再去提交事物。

	@Transactional(propagation = Propagation.REQUIRED)
    public void doServiceA() {
        // 开启事物

        //直接取调用我一来的MyServiceA 对象方法
        
        myServiceA.doServiceA();

        // 根据他是否抛出来提交事物或者回滚事物
    }
  • Propagation.REQUIRED:如果当前没有事物,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
  • Propagation.SUPPROTS:支持当前事物,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
  • Propagation.MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就跑出异常。
  • Propagation.REQUEST_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
  • Propagation.NOT_SUPPORTED:以非实物方式执行操作,如果当前存在事务,就把当前事务挂起。
  • Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • Propagation.NESTED:如果当前存在事务,则嵌套事务内执行,如果当前没有事务,则按REQUIRED属性执行。

1.6 SpringBoot的核心架构

SpringBoot原理

1.7 Spring的核心架构

spring核心架构

  • 1.实例化Bean
  • 2.设置对象属性(依赖注入)
  • 3.处理Aware接口,Spring会检测对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean。示例:如果一个Bean实现了ApplicationContextAware接口,Spring容器就会调用我们的Bean的setApplicationContext(ApplicationContext)方法,传入Spring上下文,把Spring容器传递给bean。
  • 4.BeanPostProcessor:如果想对bean进行自定义的处理,那么可以让Bean显示BeanPostProcessor接口,那么它将会调用postProcessBeforeInitialization(Object obj, String s)方法。
  • 5.InitializingBean与init-method
  • 6.执行
  • 7.DisposableBean:当bean不需要的时候,会经过清理阶段,如果bean实现了DisposableBean接口,会调用其实现的destroy方法。
  • 8.destroy-method:如果这个bean的spring配置中配置了destory-method属性,会自动调用其配置的销毁方法。

spring核心架构-1

1.8 Spring MVC

1.tomcat的工作线程将请求转交给Spring mvc框架的DispatcherServlet

2.DispatcherServlet查找@Controller注解的controller类,一般会给controller类加上@RequestMapping注解,标注说明那些controller用来处理那些请求。根据请求的url定位走到那个controller来处理。

3.根据@RequestMapping去查找,使用这个Controller内的那个方法来进行请求的处理,对每个方法一般也会加@RequestMapping注解

4.调用某个controller内的方法来进行处理。

5.controller方法会有一个返回值(json)

1.9 Spring Cloud 核心架构

SpringCloud原理分析