SSM相关

121 阅读7分钟

spring

基础

  • 核心容器:BeanFactory、ApplicationContext(继承BeanFactory)

  • 依赖注入/控制反转:对象的实例不再由调用者创建,统一交给spring管理。

  • bean的作用域:singleton、prototype(多例).

  • bean实例化:

    构造器实例化(最常用);

    静态工厂:factory-method;

    实例工厂:factory-method、fatory-bean;

  • spring可以管理singleton类型的bean的完全生命周期,对于prototype类型只负责创建,后续bean的实例交给客户端代码管理。

  • 如果BeanPostProcessor和bean关联,则bean在初始化中会调用PostProcessBeforeInitialzation()和PostProcessAfterInitialzation()方法;这个是spring的AOP实现原理。

  • 如果bean实现了InitializingBean接口,则spring初始化时将调用afterPropertiesSet()方法。

  • 如果bean实现了DisposableBean接口,则bean在被销毁时spring会调用destory()方法。

  • bean的装配方式:

    基于xml:设值注入、构造方法注入。

    基于注解: @Component、@Controller、@Service、@Repository @Autowired 默认按照类型注入,配合@Qualifer可以通过名称注入。
    @Resource 可以配置name、type属性,按照名称或类型注入。 使用注解需要配置包扫描。

    自动装配:byName、byType;默认通过名字注入。

  • bean的生命周期、启动流程 image.png

1、首先是实例化、属性赋值、初始化、销毁这 4 个大阶段;
2、再是初始化的具体操作,有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作;

执行BeanPostProcesser前置处理 --> 
执行实现了InitializingBena接口的afterPropertiesSet方法  --> 
执行BeanPostProcesser后置处理;

3、销毁的具体操作,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。

AOP

  • AOP:面向切面编程,传统的OOP只能实现父子关系的纵向复用,aop是通过横向抽取的机制实现的。

  • 目前AOP框架主要有spring AOP和 AspectJ。

    • spring的aop是在运行时通过动态代理的方式,织入横向代码;
    • AspectJ是提供的单独的编译器,在预编译期间织入横向代码。
  • spring AOP的动态代理:

    • 基于JDk的动态代理;
    • 基于CGLIB的动态代理。

spring会优先使用jdk动态代理,如果代理对象没有实现接口,则使用cglib动态代理。

  • springBoot2.0之前,不配置默认优先jdk动态代理; 从springBoot2.0(含)之后开始,如果用户默认没有配置,则默认优先使用cglib作为动态代理; 可以使用spring.aop.proxy-target-class参数控制动态代理的默认选项;

  • @Transactional注解也是通过spring的aop的实现的,通过捕获异常来控制事务的commit或rollback。

  • Spring中通过ProxyFactoryBean是创建AOP代理的最基本方式。

  • 关于动态代理的demo

// 代理工厂
public class JdkDynamicProxyFactory<T> implements InvocationHandler {

    private T target;

    public JdkDynamicProxyFactory(T target) {
        this.target = target;
    }

    public <T> T getInstance(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this
        );

    }

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

    public void myLog(){
        System.out.println("打印log....");
    }

}

// 调用
public static void main(String[] args) {
    StudySpring study = new StudySpring();
    // JdkDynamicProxyFactory factory = new JdkDynamicProxyFactory(study);
    // Improve improve = (Improve) Proxy.newProxyInstance(study.getClass().getClassLoader(), study.getClass().getInterfaces(), factory);
    // improve.study("springBoot");

    JdkDynamicProxyFactory factory = new JdkDynamicProxyFactory(study);
    Improve improve = (Improve) factory.getInstance();
    improve.study("springBoot2.0");

}
  • 切入点表达式:

返回值 包名.类名.方法名(..参数类型,两个点表示任意参数)

  • aop执行顺序:

正常场景:前置通知、环绕开始、执行业务逻辑、最终通知、环绕结束、后置通知;

异常场景:前置通知、环绕开始、最终通知、异常通知。

  • 使用AspectJ实现aop主要有:基于xml声明,基于注解声明。
xml相关配置:
<aop:config> xml配置现在基本不用了,暂不详述

基于注解:
@Aspect 定义一个切面;
@Pointcut 定义切入点表达式;对应的方法签名就是返回void,方法体为空的普通方法;
@Before 前置通知;
@AfterReturning 后置通知;
@Around 环绕通知;
@AfterThrowing 异常通知;
@After 最终通知,不管是否发生异常都会执行;

下面是个简单的demo

@Aspect  // 声明切面
@Component
public class ParamAspect {

    // 定义切点
    @Pointcut("execution(public * com.pancm.web.*.*(..))")
    public void doOperation() {

    }

    @Before("doOperation()")
    public void before(JoinPoint joinPoint) throws Throwable{
        Object[] objs = joinPoint.getArgs();
        System.out.println("前置通知接受的参数:"+(User) obj);

    }

    @AfterReturning(pointcut = "doOperation()")
    public void doAfterReturning(JoinPoint joinPoint) {
      
        System.out.println("后置通知!");
    }

  • 和注解配合使用aop
@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(ElementType.METHOD)//作用于方法
public @interface MyAnnotation {
    String methodName () default "";
}


//切面类中定义增强,pointcut连接点使用@annotation(xxx)进行定义
@Around(value = "@annotation(around)") //around 与 下面参数名around对应
public void processAuthority(ProceedingJoinPoint point,MyAnnotation around) throws Throwable{
    System.out.println("ANNOTATION welcome");
    System.out.println("ANNOTATION 调用方法:"+ around.methodName());
    System.out.println("ANNOTATION 调用类:" + point.getSignature().getDeclaringTypeName());
    System.out.println("ANNOTATION 调用类名" + point.getSignature().getDeclaringType().getSimpleName());
    point.proceed(); //调用目标方法
    System.out.println("ANNOTATION login success");
}

  • @EnableAspectJAutoProxy(proxyTargetClass=true)是Spring AOP开启的标志,proxyTargetClass来指定Spring AOP使用哪种动态代理方式来创建代理类(默认使用基于实现接口的JDK动态代理方式)。

数据库开发与事务

  • spring提供了JdbcTemplate这个bean,简化了与数据库的交互;

  • JdbcTemplate需要进行数据库的初始化配置,提供了execute()、query()、update()等方法。

  • spring中事务管理涉及3个核心接口: PlatformTransactionManager、TransactionDefinition、TransactionStatus

  • spring中事务管理分为编程式事务、声明式事务;

    • 编程式事务:通过编写代码实现的事务管理,包括定义事务的开始、事务的commit、异常时的rollback。
    • 声明式事务:通过AOP实现,推荐。
  • 声明式事务分为通过xml配置、通过注解配置。

// xml配置
<tx:advice>

// 注解方式
@Transactional
可以作用于类或方法上(不过对private方法不生效,因为无论是jdk动态代理还是cglib子类继承父类都无法对private方法进行调用)。
  • 事务的传播行为、隔离级别 可以展开了解下,目前在实践中用的比较少。

Mybatis

  • ORM框架,支持存储过程、动态sql。

  • 核心对象是SqlSessionFactory(用于生成SqlSession)、SqlSession(提供了丰富的增删改查方法、commit、rollback方法)。

  • 动态sql提供的标签

<if test=""></if>
<choose> <when test=""> <otherwise>
<where> 配合<if>使用;
<trim> 用于动态去除where条件后的and;
<set> 用于update语句;
<foreach> 用于遍历数组或集合;
<bind> 通过OGNL表达式创建一个上下文变量。
  • Mapper接口的名称和对应的Mapper.xml文件的名称必须一致。

springMVC

  • @Controller

  • @RequestMapping(value="", method="")

  • @RequestParam(value="user_id" Integer id) 前端参数映射

  • json格式包括两种:

    • {"key1":"value1","key2":"value2"....}
    • ["abc",123,false]
  • @RequestBody 用于入参的json格式化;该注解用在方法的形参上。

  • @ResponseBody 用于出参的json格式转化;该注解用在方法上。

  • RESTful风格请求,将put、delete、post、get方式分别对应添加、删除、修改、查询操作。服务端可以使用@PathVariable() 来获取url上的参数。

  • springMVC中的拦截器

实现方式有两种,实现HandlerInterceptor接口或WebRequestInterceptor接口;并且在xml中配置。
例如实现HandlerInterceptor接口,重写preHandle、postHandle、afterCompletion方法。
  • 文件上传: 前端表单需要指定multiple,后端入参中通过MultipartFile接收文件,MultipartFile提供了getInputStream、getSize、isEmpty等方法。使用List<MultipartFile 接收多文件上传。

一些注解

  • @PostConstruct注解作用是容器初始化完成后自动执行此方法,定义的是初始化方法。或者在xml配置中通过 init-method="bean中的方法名"来指定。
// 获取某个接口的所有实现类,并且找出其中用自定义注解标注的实现
Map<String, Animal> animalMap = applicationContext.getBeansOfType(Animal.class);

animalMap.values().stream().foreach(animal -> {
    MyAnnotation myAnnotation = animal.getClass().getAnnotation(MyAnnotation.class);
    if (myAnnotation != null){
        // do something
    }
});

执行顺序:

  • 实例化:调用bean的无参构造方法;
  • 属性赋值:调用set方法赋值属性;
  • BeanPostProcessor的前置处理;
  • InitializingBean方法执行;
  • 初始化:调用bean的初始化方法;
  • BeanPostProcessor的后置处理;

一些其他注解

  • @Import:用来导入其他配置类。

  • @ImportResource:用来加载xml配置文件。

  • @Value:注入Spring boot application.properties配置的属性的值。

@Value(value = “#{message}”) private String message;
  • @ExceptionHandler(Exception.class):用在方法上面表示遇到这个异常就执行以下方法。

源码学习

@Component www.cnblogs.com/wolf-bin/p/…