关于java:Spring学习笔记01

1. Spring简介

一句话概括Spring,Spring是一个开源的、轻量的管制反转(IOC)面向切面编程(AOP)的框架。

1.1 Spring、SpringMVC、Spring Boot和Spring Cloud的区别

SpringMVC是在Spring根底之上联合了MVC三层架构的框架,应用DispatchServlet和视图解析器做到了更不便的视图跳转和控制器调度解决,次要负责解决WEB利用开发。SpringMVC是Spring的一个子模块。

【腾讯云】云产品限时秒杀,爆款1核2G云服务器,首年99元

SpringBoot则应用了约定大于配置的理念,简化了Spring配置,专一于微服务的开发。

SpringCloud专一于全局微服务的整合、治理。

2. 管制反转—IOC

2.1 基本概念

IOC:管制反转,是一种设计思维。即将对象创立的控制权转移给了Spring容器

假如咱们创立了类A,类A中有个成员变量类B。

  • 传统开发:咱们须要手动创立类B的对象,将他赋给类A的对象,这叫被动管制对象的创立;
  • IOC:Spring创立好B对象,而后存储到一个容器外面,当A对象须要应用B对象时,Spring就从寄存对象的那个容器外面取出A要应用的那个B对象。

应用传统形式,A对B产生了依赖,也就是A和B之间存在一种耦合关系(假如B的实现有了改变,咱们可能还须要改变A的源码),而通过IOC的思维,这种依赖关系就被容器取代了,所有对象的创立依赖于容器,在启动的时候,Spring会读取配置文件,并将创立的对象先注入容器,之后咱们想要应用间接从容器中取就能够。

DI:依赖注入,能够了解为是Spring实现IOC的具体形式。

2.2 Spring创建对象形式

class UserService {
    private UserDao dao;
    
    public void setUserDao(UserDao dao) {
        this.userDao = dao;
    }
}

class UserDao {
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
}

2.2.1 构造函数

<bean id="dao" class="com.dong.dao.UserDao">
    <!--应用name定位构造函数-->
    <constructor-arg name="name" value="dongjh"></constructor-arg>
</bean>


<bean id="service" class="com.dong.service.UserService">
    <!--应用type定位构造函数-->
    <constructor-arg type="com.dong.dao.UserDao" ref="dao"></constructor-arg>
</bean>

注:

  1. 如果某类有无参构造方法,则默认调用无参构造方法;
  2. 如果某类只有一个构造方法,则默认调用该构造方法。

2.2.2 property(调用set办法创立)

<bean id="dao" class="com.dong.service.UserDao">
    <!--根本类型应用value注入属性-->
    <property name="name" value="dongjh"></property>
</bean>

<bean id="service" class="com.dong.service.UserService">
    <!--援用类型应用ref属性-->
    <property name="userDao" ref="dao"></property>
</bean>

注:

  1. 应用属性注入时,容器会默认调用无参构造方法创立实例,所以须要保障要创立的bean有无参的构造方法;
  2. 应用属性注入等价于调用了setXXX办法,XXX是property标签中的name,假如下面的代码的setName办法改成了setName1,则第一个bean的property需这样写:
<property name="name1" value="dongjh"></property>

2.3 Bean的主动拆卸(autowiring)

主动拆卸即Spring在上下文中主动寻找,主动给bean拆卸属性。

bean的主动拆卸次要有三种策略:

  1. byname:把与某bean(A)属性具备雷同名字的其余bean(B)主动拆卸到该bean(A)的属性中;
  2. byType:把与某bean(A)属性具备雷同类型的其余bean(B)主动拆卸到该bean(A)的属性中;
  3. constructor:把与某bean(A)的结构器入参具备雷同类型的其余bean(B)主动拆卸到该bean(A)的属性中;

2.3.1 byName

xml配置形式
<!--因为该bean的id为userDao,所以会间接主动拆卸上面service的userDao属性中-->
<bean id="userDao" class="com.dong.service.UserDao">
    <property name="name" value="dongjh"></property>
</bean>

<!--该类有setUserDao办法,且设置了属性主动拆卸byName-->
<bean id="service" class="com.dong.service.UserService" autowired="byName">
</bean>

2.3.2 byType

xml配置形式
<!--该bean的类型为com.dong.service.UserDao,所以会间接主动拆卸上面service的userDao属性中-->
<bean id="userDao111" class="com.dong.service.UserDao">
    <property name="name" value="dongjh"></property>
</bean>

<!--该类一个com.dong.service.UserDao类型的属性,且设置了属性主动拆卸byType-->
<bean id="service" class="com.dong.service.UserService" autowired="byType">
</bean>

2.4 Spring注解配置

JDK1.5开始反对注解,而Spring是2.5开始反对。

应用Spring注解配置须要先导入束缚: context名称空间和注解扫描。

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--注:只会寻找在同一个利用上下文中定义的注解,
    比方将这个申明搁置到DispatcherServlet的配置上下文中,
    它就只会查看controllers的上下文,而不会查看services的上下文,
    详情见https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-annotation-config-->
    <context:annotation-config/>
    <!--指定注解扫描返回-->
    <context:component-scan base-package="com.dong.dao"></context:component-scan>

</beans>

@Autowired

之后在须要主动拆卸的属性或set办法上应用@AutoWired注解,就能够实现主动拆卸。

//具体的可润饰范畴
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})

注:@Autowired会先应用byType,再按byName的程序主动拆卸。

@Autowired有一个罕用属性:required,默认值为true,这个属性示意润饰的成员变量是否肯定须要拆卸一个bean:

  • 当required设置为true时,示意必须有一个能够主动拆卸到该成员变量的bean,否则报错;
  • 当required设置为false时,则示意该成员变量能够为null;

@Qualifier

当有多个bean满足主动拆卸条件时,能够应用这个指定拆卸的bean,个别配合@Autowired应用。

@Qualifier有个属性value,给这个value设置想要拆卸的bean的id即可。

@Component

润饰类,示意将该类的bean对象注入到Spring容器中。

@Component有个属性value,示意注入时设置的id。

如:

//等价于<bean id="user" class="User">
@Component(value="user")
public class User {}

@Component有一些衍生注解,如Web开发会依照MVC架构分层,依据不同的性能层,衍生出了一些注解:

  • @Repository:针对dao层
  • @Service:针对service层
  • @Controller:针对controller层

这四个注解性能统一,都示意将某类的bean对象注入到Spring容器中。

@Value

给属性注入值,次要用于给成员变量注入值,简略的能够注入根本类型的值,简单时能够注入一些操作系统属性或其余bean的属性。

@Scope

用于设置bean的作用域,先介绍最常见的:

  • singleton:全局惟一,单例;
  • prototype:每次注入创立一个新的对象。

注解和配置的区别

xml性能更加弱小,方便管理保护。注解实用于简略的属性注入。

2.5 JavaConfig配置

Spring 3.0之后开始反对了一种更优的配置形式:基于Java类的配置形式。通过减少@Configuration注解表明这是一个配置类,其底层为@Component(即该类的bean对象也会被Spring容器接管)。

@Configuration联合@Bean注解能够实现XML配置实现注入的性能,成果与

<beans>
    <bean>...</bean>
    <bean>...</bean>
</beans>

相似,在应用@Bean注解时,示意将该办法返回的对象加载进Spring容器,在应用@Bean润饰办法时须要留神:

  1. 办法带返回值,且返回类型为想要被治理的bean的类型;
  2. 办法名即为默认的bean name,可应用@Bean的name属性自定义;
  3. 办法可带参数,则此时传入的参数也必须是被Spring容器治理的bean

以创立UserService和UserDao为例:

@Configuration
public class UserConfiguration {
    @Bean
    public UserService userService() {
        return new UserService();
    }
    
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}

当Spring扫描该类时,会主动将UserConfiguration、UserService、UserDao的bean注入到Spring容器中进行托管。

3. 面向切面编程—AOP

3.1 基本概念

在软件开发中,咱们须要编写许多的业务代码,但还有很多代码是业务无关的,如

  • 日志性能
  • 缓存清理
  • 资源回收
  • 权限查看

为了实现业务代码和非业务代码的拆散,Spring利用代理模式抽出了非业务代码,造成了AOP思维。

AOP全称Aspect Oriented Programming,意为面向切面编程,假如业务代码自身是一条纵向的逻辑流,咱们在其中找几个点(切点,Pointcut),插入非业务代码,就像是一个个切面(Aspect),这就是一个简略的AOP例子。

切面和切点很容易被混同,严格来说,切点是切面的一部分信息,切面次要蕴含两局部信息:

  • 切入点;
  • 切入后要执行的动作(Advice)。

而在具体的实现中,Spring为切面还加了一个信息:在切点的哪个阶段执行?由此衍生出有:

  • 前置告诉(Before):在指标办法被调用之前调用告诉性能;
  • 后置告诉(After):在指标办法被调用之后调用告诉性能;
  • 返回告诉(After-returning):在指标办法胜利执行之后调用告诉;
  • 异样告诉(After-throwing):在指标办法抛出异样后调用告诉;
  • 盘绕告诉(Around):告诉包裹了被告诉的办法,在被告诉的办法调用之前和调用之后执行自定义的行为。

对于AOP在Spring的实现有三种形式:

  1. 实现原生的Spring API接口
  2. 自定义切面类
  3. 注解

3.2 实现原生Spring API接口

Spring提供了诸如MethodBeforeAdvice、AfterAdvice、AfterReturningAdvice等原生接口,咱们能够通过实现这些接口构建切面,如

@Component
public class Log implements MethodBeforeAdvice {
    /**
     * @param method  要执行的指标对象办法
     * @param objects 参数
     * @param o       指标对象
     * @throws Throwable
     */
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName() + "-" + method.getName() + "将要执行");
    }
}

该Log类实现了MethodBeforeAdvice,成为了一个在办法执行前插入的切面,其次,咱们须要在XML中进行配置,设置切点并建设其和切面的连贯:

<aop:config>
    <!--切入点:execution表达式,execution(要执行的办法!)-->
    <aop:pointcut id="pointcut" expression="execution(* com.dong.service.UserServiceImpl.*(..))"/>
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
</aop:config>

execution示意在办法执行时触发;*示意办法返回值能够是任意类型,com.dong.service.UserServiceImpl.*应用全限定类名和办法名指定要增加前置告诉的办法,应用*示意对com.dong.service.UserServiceImpl类下的所有办法都执行切入;(..)示意办法的参数列表,应用(..)示意办法的入参能够是任意类型。

须要留神,Log必须是一个被Spring容器治理的bean对象,否则Spring将无奈找到该切面的bean,因而应用@Component注解润饰(也能够应用XML配置等形式注入)。

3.3 自定义切面类

自定义切面不须要实现Spring的原生接口,首先须要定义一个切面类,并将加载给Spring容器进行托管。

@Component(value="diy")
public class DiyPointCut {
    public void before() {
        System.out.println("办法执行前");
    }

    public void after() {
        System.out.println("办法执行后");
    }
}

与3.2类似,该形式须要通过XML配置设置切点以及其和切面的连贯。

<aop:config>
    <!--自定义切面,ref:要援用的bean-->
    <aop:aspect ref="diy">
        <aop:pointcut id="pointcut" expression="execution(* com.dong.service.UserServiceImpl.*(..))"/>
        <!--指定advice和切点的关系-->
        <aop:before method="before" pointcut-ref="pointcut"></aop:before>
        <aop:after method="after" pointcut-ref="pointcut"></aop:after>
    </aop:aspect>
</aop:config>

3.4 注解

3.4.1 启用注解性能

首先,应用注解有两种形式:

  1. XML导入配置:

    <?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:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--启用注解-->
        <context:annotation-config/>、
        <!--注解包扫描-->
        <context:component-scan base-package="com.dong.dao"></context:component-scan>
        <context:component-scan base-package="com.dong.log"></context:component-scan>
        <!--启用aop注解-->
        <aop:aspectj-autoproxy proxy-target-class="true"/>
    </beans>
  2. 应用@EnableAspectJAutoProxy注解须要被切的类

    @Component(value = "userService")
    @EnableAspectJAutoProxy
    public class UserServiceImpl implements UserService {}

其次,应用注解时,须要留神两局部:

  • 申明切面:申明某类是切面以及切入后理论要执行的动作(Advice);
  • 定位切点:须要通过execution表达式定位须要切入的办法。

上面介绍一下注解的应用形式。

3.4.2 注解应用

只有对一个类应用@Aspect注解润饰,就表明这是一个切面。能够对其中的办法应用

  • @Before
  • @After
  • @AfterReturning
  • @Around
  • @AfterThrowing

注解指定切入机会,切入点通过execution表达式指定,举例如下:

@Aspect
@Component
public class CustomPointCut {
    @Before("execution(* com.dong.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("aop:办法产生前");
    }
}

4. 参考资料

  1. Spring最新5残缺教程
  2. Spring入门(十):Spring AOP应用解说
  3. Spring AOP – 注解形式应用介绍

阿里云限时活动-2核2G-5M带宽-40-100G SSD服务器,特惠价86元/年(原价724元/年,限时99元续购三次),速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

You may also like...

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据