java component 构造函数_【Java劝退师】Spring 知识脑图 - 全栈开源框架

本文介绍了Spring框架的核心概念,包括IOC容器、依赖注入、面向切面编程等,并详细阐述了如何利用这些技术来简化Java应用程序的开发流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

f4557529608987d9e7a5f6c079f090ee.png

3e4b9c1b7571e76b4721c71f066685b2.png

Spring 笔记

一、解决的问题

1. IOC 解偶

透过 Spring 的 IOC 容器,将对象间的依赖关系交给 Spring 来控制,避免硬编码造成的程序耦合。

2. 简化 AOP 编程

透过 Spring 的 AOP 功能,让我们可以更方便地进行面向切面编程。

3. 声明式事务 @Transaction

可以通过注解方式进行事务控制。

4. 集成各种框架、API,降低使用难度

框架 : Struts、 Hibernate、MyBatis、 Hessian、Quartz

API : JDBCTemplate、 JavaMail、RestTemplate

二、核心思想

1. IOC Inversion of Control 控制反转

将 Java 对象的创建、管理的权力 交给第三方 (Spring 框架)

目的 : 解偶

原理 : 透过反射调用无参构造函数实例化对象并存到容器中。【没有无参构造将实例化失败】

2. DI Dependancy Injection 依赖注入

将被管理的 Java 对象注入给某个属性

目的 : 解偶

原理 : 使用反射技术设置目标对象属性

3. AOP Aspect oriented Programming 面向切面编程

一种横向抽取技术,在特定的方法前、方法后,运行特定的逻辑

目的 : 减少重复代码

应用场景 : 事务控制、权限较验、日志纪录 、性能监控

三、特殊类

  1. BeanFactory - 容器类的顶层接口 - 基础规范
    1. ApplictaionContext - 容器类的高级接口 - 国际化、资源访问( XML、配置类 )
      1. ClassPathXmlApplicationContext - 项目根路径下加载配置文档
      2. FileSystemXmlApplicationContext - 硬盘路径下加载配置文档
      3. AnnotationConfigApplicationContext - 从注解配置类加载配置
  1. FactoryBean - 自定义复杂 Bean 的创建过程
  2. BeanFactoryPostProcessor - BeanFactory 初始化完成后,进行后置处理
  3. BeanPostProcessor - Bean 对象实例化、依赖注入后,进行 Bean 级别的后置处理

四、注解

1. IOC 类型

  1. @Component("Bean的ID") 【类上】 - 默认 ID 为类名首字母小写,等价以下三个注解
    1. @Controller
    2. @Service
    3. @Repository
  1. @Scope("Bean的生命周期") 【类上】
    1. singleton【默认】- 与容器生命周期相同
    2. prototype - 每次获取都是新的
    3. request - 一个HTTP请求范围内相同
    4. session - Session 范围内相同
    5. globalSession - portlet-based 应用范围内相同
  2. @PostConstruct 【方法上】- 初始化后调用
  3. @PreDestory 【方法上】- 销毁前调用

2. DI 类型

  1. @Autoweird - 依照类型注入
    类型对应的对象非唯一时,可以搭配 @Qualifier(name="Bean的ID") 使用
  2. @Resource(name="Bean的ID", type=类) - 默认依照ID注入,如果ID找不到则按类型注入

3. 配置类型

  1. @ComponentScan - 需要扫描的包路径
  2. @Configuration - 标明此类是配置类
  3. @PropertySource - 引入外部配置文档
  4. @Import - 加载其它配置类
  5. @Value - 将配置文档的数据赋值到属性上
  6. @Bean - 将方法返回的对象存入 IOC 容器中,对象ID为方法名,也可以手动指定

4. AOP 类型

  1. @Pointcut - 配置切入点
  2. @Before - 前置通知
  3. @AfterReturning - 后置通知
  4. @AfterThrowing - 异常通知
  5. @After - 最终通知
  6. @Around - 环绕通知

五、AOP

1. 术语

  1. Joinpoint 连接点 : 所有的方法
  2. PointCut 切入点 : 具体想要影响的方法
  3. Advice 通知/增强 : 横切逻辑
  4. Target 目标 : 被代理对象
  5. Proxy 代理 : 被 AOP 织入增强后的类
  6. Weaving 织入 : 把 Advice 应用到 Target 产生 Proxy 的过程
  7. Aspect 切面 : 切入点 + 增强

目的 : 为了锁定在哪个地方插入什么横切逻辑

@Component
@Aspect
public class LogUtil {
    
     /**
     * 切入点表达式 
     * [访问修饰符] 返回值 包名.包名.包名.类名.方法名(参数表表)
     * 
     * 【.】 用在包,表示任意包,有几级包写几个
     * 【..】用在包,表示当前包及其子包
     *
     * 【..】用在参数表表,表示有无参数均可
     * 【*】 用在参数表表,表示至少一个参数
     */
     @Pointcut("execution(* com.lagou.service.impl.*.*(..))")
     public void pointcut(){}
    
     @Before("pointcut()")
     public void beforePrintLog(JoinPoint jp){
         Object[] args = jp.getArgs();
         System.out.println("前置通知:beforePrintLog,参数是:" + Arrays.toString(args));
     }
    
     @AfterReturning(value = "pointcut()",returning = "rtValue")
     public void afterReturningPrintLog(Object rtValue){
         System.out.println("后置通知:afterReturningPrintLog,返回值是:"+ rtValue);
     }
    
     @AfterThrowing(value = "pointcut()",throwing = "e")
     public void afterThrowingPrintLog(Throwable e){
      System.out.println("异常通知:afterThrowingPrintLog,异常是:"+ e);
     }
    
     @After("pointcut()")
     public void afterPrintLog(){
      System.out.println("最终通知:afterPrintLog");
     }
    
     /**
     * 环绕通知
     */
     @Around("pointcut()")
     public Object aroundPrintLog(ProceedingJoinPoint pjp){
         
         // 定义返回值
         Object rtValue = null;
         try{
             
             // 前置通知
             System.out.println("前置通知");
             
             // 1.获取参数
             Object[] args = pjp.getArgs();

             // 2.运行切入点方法
             rtValue = pjp.proceed(args);

             // 后置通知
             System.out.println("后置通知");
             
         } catch (Throwable t){
             
             // 异常通知
             System.out.println("异常通知");
             t.printStackTrace();
             
         }finally {
             
             // 最终通知
             System.out.println("最终通知");
             
         }
         return rtValue;
     }
}

六、声明式事务 @Transaction

1. 四大特性

原子性 Atomicity : 操作要码都发生,要码都不发生

一致性 Consistency : 数据库从一个一致状态变换到另一个一致状态

隔离性 Isolation : 事务不能被其它的事务所干扰

持久性 Durability : 数据的改变是永久性的

2. 隔离级别

脏读 : 读取到另一个线程未提交的数据 - Read Committed 读已提交

不可重复读 : 读到另一个线程 update 的数据,两次读取到的数据 内容 不一样 - Repeatable Read 可重复读

幻读 : 读取到另一个线程 insert 或 update 的数据,两次读取到的数据 数量 不一样 - Serializable 串行化

3. 传播行为

  1. REQUIRED【默认】 - 当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加入到这个事务中
  2. SUPPORTS - 支持当前事务,如果当前没有事务,就以非事务方式运行 - 查找
  3. MANDATORY - 使用当前的事务,如果当前没有事务,就抛出异常
  4. REQUIRES_NEW - 新建事务,如果当前存在事务,把当前事务挂起
  5. NOT_SUPPORTED - 以非事务方式运行操作,如果当前存在事务,就把当前事务挂起
  6. NEVER - 以非事务方式运行,如果当前存在事务,则抛出异常
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)

4. 失效场景

  1. 应用在非 public 修饰的方法上
  2. 同一个类中方法调用
  3. 异常被 try catch 吃掉
  4. propagation 设置错误
  5. rollbackFor 设置错误
  6. 数据库引擎不支持事务

5. 原理

透过 JDK 动态代理 与 Cglib 动态代理 实现,数据库事务归根结柢是Connection的事务。

Connection是从连接池(C3P0、Druid)拿来的,Connection可以产生prepareStatement,preparedStatement可以运行execute()方法直接运行SQL语句。

在 JDK 1.8 的环境下,JDK 动态代理的性能已经优于 Cglib 动态代理,但缺点是使用 JDK 动态代理的被代理类需要至少实现一个接口。

1. JDK 动态代理

被代理类至少需实现一个接口

public class JdkDynamicProxyTest implements InvocationHandler {

    private Target target;

    private JdkDynamicProxyTest(Target target) {
        this.target = target;
    }

    public static Target newProxyInstance(Target target) {
        return (Target) Proxy.newProxyInstance(JdkDynamicProxyTest.class.getClassLoader(),
                new Class<?>[]{Target.class},
                new JdkDynamicProxyTest(target));

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }
}

2. Cglib 动态代理

通过字节码底层继承要代理类来实现

public class CglibProxyTest implements MethodInterceptor {

    private CglibProxyTest() {
    }

    public static <T extends Target> Target newProxyInstance(Class<T> targetInstanceClazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetInstanceClazz);
        enhancer.setCallback(new CglibProxyTest());
        return (Target) enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        return proxy.invokeSuper(obj, args);
    }

}

测试

Target targetImpl = new TargetImpl();
Target dynamicProxy = JdkDynamicProxyTest.newProxyInstance(targetImpl);
Target cglibProxy = CglibProxyTest.newProxyInstance(TargetImpl.class);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值