Spring 理解

Spring 个人理解

1.概念
一个轻量级开源框架,拥有多个组件(Spring JDBC 、Spring MVC 、Spring Security(可用作单点登入)、 Spring AOP 、Spring ORM 、Spring Test),主要解决业务逻辑层与其他各个层的耦合问题,因此将面向接口编程贯彻整个系统应用,核心即控制反转Ioc与面向切面编程Aop,最为典型的当属数据库事务的使用,还能整合开源世界众多著名的第三方框架和类库,应该说Spring框架已经融入到了Java EE的各个开发领域。

2.优势
2.1简化开发
是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 容器管理,降低了组件之间的耦合性
2.2声明式事务的支持
通过配置就可以完成对事物的管理,而无须手动编程, 提高开发效率和质量。
2.3便于集成其他框架
其内部提供了对各种优秀框架的直接支持(如MyBatis、Hibernate)。
2.4降低 Java 开发难度
2.5包括了 J2EE 三层的每一层的解决方案(一站式)

3.作用
①.Spring 能帮我们根据配置文件创建及组装对象之间的依赖关系。
②.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
③.Spring 能非常简单的帮我们管理数据库事务。
④.Spring 还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板来方便数据库访问。
⑤.Spring 还提供与第三方Web(如Struts1/2、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
⑥.Spring 能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。

4.框架结构
在这里插入图片描述
Spring IOC: (控制反转\依赖注入)
不是一种技术,而是一种设计思想,将对象的控制权交spring容器,最直观的是对象创建不需要去new,spring容器使用反射机制根据配置文件动态的去创建和管理对象,最大的改变不是从代码上,而是思想上发生了“主从换位”,应用程序(老大)变成被动,等待ioc来创建它所需要的资源。

//实现demo
public class client {
 
	public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, JDOMException, IOException {
		BeanFactory factory = new ClassPathXmlApplicationContext(); 
		//通过工厂直接获取
      	UserService userService = (UserService) factory.getBean("userService"); 
        //其实User也可以从工厂中获得
        User u=(User)factory.getBean("user");
        //User u = new User();  
        u.setUserName("yyb");  
        u.setPassword("1234");  
        userService.addUser(u);//打印结果yyb1234
	}
 
}

DI(依赖注入)
 IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。 Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性。
注入方式:

①:构造器注入、②setget注入、③注解注入、④静态工厂方法注入、⑤动态工厂方法注入

总结:控制反转IoC是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方。

Spring AOP: (面向切面编程)
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率(通俗理解spring用代理类包裹切面,把他们织入到Spring管理的bean中。也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用伪装类,伪装类中就先执行了切面,再把调用转发给真正的目标bean)。

组成

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理在这里插入图片描述
    在这里插入图片描述
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、 - 异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
    在这里插入图片描述
    通知常见应用场景
    在这里插入图片描述
    实现aop面向切面编程demo

1. 引入pom依赖

<dependencies>
    <!--导入spring的context坐标,context依赖aop-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.5.RELEASE</version>
    </dependency>
    <!-- aspectj的织入 -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.13</version>
    </dependency>
        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.10.RELEASE</version>
        </dependency>
    </dependencies>

2. 创建目标接口

package com.aop;

/*
 *目标接口
 */
public interface TargetInterface {
    void method();
}

3. 创建目标类实现目标接口

package com.aop;

import org.springframework.stereotype.Component;

/*
 *目标类
 */
@Component
public class Target implements TargetInterface {
	public void method() {
	 //int i = 1/0; //算术异常(用于测试异常通知): ArithmeticException
	    System.out.println("method方法执行");
	}
}

4. ①创建切面类,该类添加@Aspect注解表明该类为切面类;②将切面类与目标类交由Spring管理,添加@Component注解;③在切面类中使用注解配置织入关系(个人理解为需要增强的方法路径)

package com.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/*
        切面类,配置通知的类
*/

@Component
@Aspect
public class MyAspect {

    //前置通知
    @Before("execution(* com.aop.*.*(..))")
    public void before(){
        System.out.println("前置通知执行---");
    }

    //后置通知
    @AfterReturning("execution(* com.aop.*.*(..))")
    public void afterReturning(){
        System.out.println("后置通知执行---");
    }

    //环绕通知,需要显示调用,否则不执行目标方法,ProceedingJoinPoint必须在第一个形参位置上
    @Around("execution(* com.aop.*.*(..))")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("环绕通知---前执行");
        Object proceed = pj.proceed();
        System.out.println("环绕通知---后执行");
        return proceed;
    }

    //异常通知
    @AfterThrowing("execution(* com.aop.*.*(..))")
    public void afterThrowing(){
        System.out.println("异常通知执行---");
    }

    //最终通知
    @After("execution(* com.aop.*.*(..))")
    public void after(){
        System.out.println("最终通知执行---");
    }

}

在application.xml中开启组件扫描和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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">

    <!--组件扫描-->
    <context:component-scan base-package="com.aop"/>

    <!--aop自动代理-->
    <aop:aspectj-autoproxy/>

</beans>
package com.aop;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/*
 * aop测试
 */

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private TargetInterface targetInterface;

    @Test
    public void test1(){
        targetInterface.method();
    }
}

代理
代理是设计模式的一种,其原理就是通过代理对象去访问目标对象,而外部只能访问到代理对象(目的是构造一个和被代理的对象有同样行为的对象,一个对象的行为是在类中定义的,对象只是类的实例。所以构造代理,不一定非得通过持有、包装对象这一种方式。)

JDK动态代理

要生成一个包装类对象,只能对实现了接口的类生成代理,不能针对类,代理对象是动态的,所以称之为jdk动态代理,JDK动态代理是“对象”的代理。(开发过程中,需要对目标类增强,代理类不能直接包含被代理对象,而是通过代理类实现InvocationHandler接口,该接口包含被代理对象,负责分发请求给被代理对象,分发前后均可做增强)

CGLIB动态代理

通过继承父类所有的公开方法,然后可以重写这些方法,在重写时对这些方法增强,这就是cglib的思想。根据里氏替换原则,是针对类的实现代理,对指控的类生成一个子类,无法对声明为final的方法进行代理。

实现两种代理—demo
1.创建代理类

package com.aop.factory;

import com.alibaba.fastjson.JSON;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
  * jdk代理
  */
public class JdkProxy implements InvocationHandler {

    //代理对象
    private Object target;
	
    public JdkProxy(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("传入参数args.toString())");
        Object invoke = method.invoke(target, args);
        System.out.println("结果集" + JSON.toJSONString(invoke));
        return invoke;
    }

	//回调代理对象
    public Object getProxy() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}
package com.aop.factory;

import com.aop.service.impl.UserServiceImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * cglib代理
 */
public class CglibProxy implements MethodInterceptor {

    //代理对象
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
        System.out.println("Before:" + method);
        //回调被代理对象(obj)
        Object object = proxy.invokeSuper(obj, arg);
        System.out.println("After:" + method);
        return object;
    }

    //回调代理对象
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(new CglibProxy(target));
        return enhancer.create();
    }

}

2.创建接口

package com.aop.service;

public interface UserService {

    void add();

    void del();

    String getById(String id);

}

3.创建接口实现类

package com.aop.service.impl;

import com.aop.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {


    @Override
    public void add() {
        System.out.println("add");
    }

    @Override
    public void del() {
        System.out.println("del");
    }

    @Override
    public String getById(String id) {
        System.out.println("getById" + id);
        return null;
    }
}

4.测试输出

package com.aop;

import com.aop.factory.JdkProxy;
import com.aop.service.UserService;
import com.aop.service.impl.UserServiceImpl;

public class Test {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        //根据目标类userService,通过代理类创建代理对象proxy
        UserService proxy = (UserService) new JdkProxy(userService).getProxy();
        proxy.add();
        proxy.del();
        proxy.getById("123123");
    }
}

Spring的bean生命周期
在这里插入图片描述
主要分四个步骤:①初始化;②属性赋值;③初始化;④销毁
1.spring容器获取Bean(类)信息并且实例化;
2.通过依赖注入,配置所有Bean属性;
3.若实现了BeanNameAware接口,会调用setBeanName()方法传递Bean的Id;
4.若实现了BeanFactoryAware接口,会调用setBeanFactory()方法传递工厂自身;
5.若实现了ApplicationContextAware接口,会调用setApplicationContext()方法,该步骤也可实现步骤4,比步骤4更好;
6.若关联了BeanPostProcessor接口,进行预初始化;
7.若关联了InitializingBean接口,声明初始化,全部属性设置成功后,执行初始化方法;
8.若关联了BeanPostProcess接口,进行后初始化;
9.Bean不在需要时会进行销毁,若实现了DisposableBean接口,会调用destroy()方法,执行回调。

5.事务
四大特性

原子性:
概念型理解:事务是不可分割的一部分,要么同时执行成功,要么集体回滚,比如一个方法中管理了多个方法,如果其中有一个执行失败,集体回滚。
业务型理解:我有一百块钱,给你转五十,转账过程中出现问题,不会扣除我的钱,你的钱也不会增加。
一致性:
概念型理解:是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
业务型理解:我有一百块钱,给你转五十,我还剩五十,咱们两个相加还是一百。
隔离性:
概念型理解:事务之间是相互隔离,互相不受打扰。
业务型理解:我给你转账的过程中,是不允许立马执行查询的,必须等待转账成功后,再执行查询的操作。
排它锁、行级锁、表级锁
持久性:
概念型理解:事务一旦提交,不再执行修改事务的情况下,它就是永久性的保存的。
业务型理解:服务器宕机了,电脑坏掉了,数据还有吗?一定是有的,因为它持久化了。

不考虑隔离性引发的安全性问题:
脏读:一个事务读到了另一个事务未提交的数据
不可重复读:一个事务督导另一个事务已经提交的update的数据导致多次查询结果不一致
虚幻读:一个事务读到了另一个事务已经提交的insert的数据导致多次查询结果不一致。

四大隔离级别
使用: @Transactional(isolation = Isolation.READ_COMMITTED)

未提交读(read uncommited):脏读,不可重复读,虚读都有可能发生;
已提交读(read commited):避免脏读。但是不可重复读和虚读都有可能发生;
可重复读(repeatable read):避免脏读和不可重复读,但是虚读有可能发生;
串行化的(serializable):避免以上所有读问题。
MySQL默认:可重复读
Oracle默认:已提交读

七大传播
Spring事务传播机制

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值