Spring知识详解

1 Spring

1.1简介

  • Spring:春天——>给软件行业带来了春天!
  • 2002年,首次推出了Spring框架的雏形,interface21框架!
  • Spring框架即以Interface21框架为基础 ,经过重新设计,并不断丰富起内涵,于2004年3月24日,发布了1.0正式版。
  • Rob Johnson,Spring Framework创始人,著名作者,很难想象Rob Johnson的学历,真的让 好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学 ;
  • Spring理念:使现有的技术更加容易,本身是一个大杂烩 。

1.2优点

  • Spring是一个免费的开源的容器;
  • Spring是一个轻量级的、非入侵式的框架;
  • 控制反转(IOC)、面向切面编程(AOP);
  • 支持事务的处理,对框架整合的支持;

总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。

2 IOC理论推导

  1. UserDao接口

    public interface UserDao {void UserList();
    }
    
  2. UserDaoImpl实现类

      public void UserList() {System.out.println("获取用户所有信息");}
    
  3. UserSerivce业务接口

    public interface UserService {void UserListService();
    }
    
  4. UserServiceImpl实现类

       UserDao userDao;public void setUserDao(UserDao userDao){this.userDao=userDao;}public void UserListService() {userDao.UserList();}
    }
    

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求修改源代码。如果程序代码量非常大,修改一次的成本代价非常昂贵。

我们使用一个set接口实现,已经发生了革命性的变化;

 public void setUserDao(UserDao userDao){this.userDao=userDao;}
  • 之前,程序是主动创建对象,控制权在程序猿手上;
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接受对象;

这种思想,从本质上解决了问题,我们不用再去管理对象的创建了。系统的耦合性降低,可以专注在业务上。这是IOC的原型。

2.1IOC本质

控制反转IOC(Inversion of control)是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得 依赖对象的方式反转了。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注释)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency injection,DI)。

3HelloSpring

所谓的IOC,一句话搞定,就是:对象由Spring来创建、管理、装配。

思考问题?

  • Hello对象是谁创建的?

    Hello对象是由Spring创建的

  • Hello对象的属性 是怎么设置的?

    Hello对象的属性是由Spring容器设置的

这个过程就叫做控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制的,使用Spring后,对象是由Spring来 创建的。

反转:程序本身不创建对象,而编程被动的接收对象

依赖注入:就是利用set方式来进行注入的

IOC是一种编程思想,由主动的编程变成被动的接收

4IOC创建对象的方式

  1. 使用无参构造创建对象,默认!

  2. 假设我们要使用有参构造创建对象;

    1. 下标赋值:

       <bean id="User" class="com.pledge.pojo.User"><constructor-arg index="0" value="pledge"/>bean>
      
    2. 通过类型创建对象

        <bean id="User" class="com.pledge.pojo.User"><constructor-arg type="java.lang.String" value="wufenfen"/>bean>
      
    3. 直接通过参数名创建对象

      <bean id="User" class="com.pledge.pojo.User"><constructor-arg type="java.lang.String" value="wufenfen"/>bean>
      

    总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!

5Spring配置

5.1别名

 <alias name="User" alias="UserNew"/>

5.2Bean配置

<bean id="user" class="com.pledge.pojo.User" name="user2,u2"><property name="name" value="plegde"/>bean>

5.3import

这个import,一般用于团队开发使用,可以将多个配置文件,导入合并为一个。

6依赖注入

6.1构造器注入

6.2set方法注入

  • 依赖注入:set注入
    • 依赖:bean对象 的创建依赖容器
    • 注入:bean对象中的所有属性,由容器来注入

6.3拓展方式注入

【环境搭建】

  1. 复杂类型

    public class Address {    rivate String address;    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }}
    
  2. 真实测试对象

    public class Student {private String name;private Address address;private String[] books;private List<String> hobbys;private Map<String,String> card;private Set<String> games;private Properties info;private String wife;
    
  3. beans.xml

    
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="student" class="com.pledge.pojo.Student"><property name="name" value="鲍玉静"/>bean>
    beans>
    
  4. 测试类

    public class MyTest {public static void main(String[] args) {ApplicationContext context= new ClassPathXmlApplicationContext("beans.xml");Student student=(Student)context.getBean("student");System.out.println(student.getName());}
    }
    

完善注入信息

  <bean id="address" class="com.pledge.pojo.Address">        <property name="address" value="address"/>    bean>    <bean id="student" class="com.pledge.pojo.Student">        <property name="name" value="鲍玉静"/>        <property name="address" ref="address"/>        <property name="books">            <array>                <value>《西游记》value>                <value>《红楼梦》value>                <value>《水浒传》value>            array>        property>        <property name="hobbys">         <list>             <value>睡觉value>             <value>玩游戏value>             <value>学习value>         list>        property>        <property name="card">            <map>                <entry key="身份证" value="132746324"/>                <entry key="银行卡" value="8467573285675647"/>            map>        property>        <property name="games">            <set>                <value>LOLvalue>                <value>BOBvalue>                <value>COCvalue>            set>        property>        <property name="wife">            <null />        property>        <property name="info">            <props>                <prop key="学号">137264prop>                <prop key="性别">prop>            props>        property>    bean>

7 Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式!
  • Spring会在上下文中自动寻找,并自动给Bean装配属性!

在Spring中有三种装配的方式

  1. 在xml中显示的配置;
  2. 在java中显示配置
  3. 隐式的自动装配bean【重要】

7.1测试

环境搭建:一个人有两个宠物!

7.2ByName自动装配

 <bean id="people" class="com.pledge.pojo.People" autowire="byName"><property name="name" value="pledge"/>bean>

7.3ByType自动装配

 <bean id="people" class="com.pledge.pojo.People" autowire="byType"><property name="name" value="pledge"/>bean>

总结:

  • ByName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性和set方法的值一致!
  • ByType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。

7.4使用注解实现自动装配

jdk1.5支持的注解,Spring2.5就支持注解了。

要使用注解须知:

  1. 导入约束;(context约束必须要导入)

  2. 配置注解的支持;context:annotation-config/

    
    <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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:annotation-config/>
    beans>
    

    @Autowired

    直接在属性上使用即可,也可以在set方式上使用!(可以忽略set方法使用)

    使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字ByName。

    科普:

    @Nullable 字段标记了这个注解,说明这个字段可以为null
    
    public @interface Autowired{    boolean required() default true;}
    
        //如果显示定义了Autowired的required属性为false,说明这个对象可以为null;否则不允许为空    @Autowired(required = false)    private Dog dog;    @Autowired    private Cat cat;    private String name;
    

    如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【Autowired】完成的时候,我们可以使用@Qualifier(value=“xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!

    public class People {    //如果显示定义了Autowired的required属性为false,说明这个对象可以为null;否则不允许为空    @Autowired    private Dog dog;    @Autowired    @Qualifier(value = "cat1")    private Cat cat;    private String name;
    

    @Resource注解

    public class People {//如果显示定义了Autowired的required属性为false,说明这个对象可以为null;否则不允许为空@Resource(name="dog1")private Dog dog;@Resourceprivate Cat cat;private String name;
    

    小结:

    @Resource和@Autowired的区别:

    • 都是用来自动装配的,都可以放在属性字段上;
    • @Autowired通过ByType的方式实现,而且必须要求这个对象存在;
    • @Resource默认通过ByName的方式实现,如果找不到名字,则通过ByType实现;如果两个都找不到的情况,就报错!
    • 执行顺序不同:@Autowired通过Type的方式实现,@Resource默认通过ByType的方式实现。

8使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

使用注解需要导入context约束,增加注解的支持!

  1. bean

  2. 属性如何注入

    @Componentpublic class User {    @Value("吴芬芬")    public String name;}
    
  3. 衍生的注解

    @Component有几个衍生注解,我们在web开发中,会按照MVC三层架构分层!

    • dao【@Repository】

    • controller【@Controller】

    • service【@Service】

      这四个注解功能都是一样的,都是代表将某个类注册到容器中,装配Bean

  4. 自动装配

  5. 作用域

  6. 小结

    xml与注解:

    • xml更加万能,适用于任何场合,维护简单方便;
    • 注解不是自己的类使用不了,维护相对复杂;

    xml与注解最佳实践:

    • xml用来管理bean;
    • 注解只负责完成属性的注入;
    • 我们在使用的过程中,只需要注意一个问题,必须让注解生效,就需要开启注解的支持
    <context:component-scan base-package="com.pledge"/><context:annotation-config/>
    

    9 使用Java的方式配置Spring

    我们现在要完全不使用Spring的xml配置了,全权交给Java来做!

    JavaConfig是Spring的一个子项目,在spring4之后,它成为了一个核心功能。

    实体类

    @Component
    public class User {@Value("吴芬芬")  //属性private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
    }
    
    @Configuration//这个也会被Spring容器托管,注册到容器中,因为它本来就是一个@Component
    //@Configuration代表这是一个配置类,就和我们之前看到的beans.xml是一样的
    @ComponentScan("com.pledge.pojo")
    @Import(PledgeConfig.class)
    public class PledgeConfig {//注册一个bean,就相当于我们之前写的一个Bean标签,id是这个方法的名字//就相当于bean标签中的id属性//这个方法的返回值,就相当于bean标签中的class属性@Beanpublic User getUser(){return new User();  //就是返回要注入到bean的对象}
    }
    
    public class MyTest {public static void main(String[] args) {//如果完全使用了配置类方式去做,我们就只能通过annotationConfig上下文来获取容器ApplicationContext context = new AnnotationConfigApplicationContext(PledgeConfig.class);User user=(User)context.getBean("getUser");System.out.println(user.getName());}
    }

    这种纯java的配置方式,在SpringBoot中随处可见!

9代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层【SpringAOP和SpringMVC】

代理模式的分类:

  • 静态代理
  • 动态代理

9.1静态代理

角色分析:

  • 抽象角色:一般会使用接口或抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色、代理真实角色后,一般会做一些附属操作。
  • 客户:访问代理对象的人

代码步骤:

接口

//租房public interface Rent {    public void rent();}

真实角色

//房东public class Host implements Rent{    public void rent(){        System.out.println("房东要出租房子");    }}

代理角色

public class Proxy implements Rent{private Host host;public Proxy(){};public Proxy(Host host) {this.host = host;}public void rent(){seeHouse();host.rent();hetong();fare();}public void seeHouse(){System.out.println("中介带你看方");}public void hetong(){System.out.println("签租赁合同");}public void fare(){System.out.println("中介收中介费");}
}

客户端访问代理角色

public class Client {public static void main(String[] args) {//房东要租房子Host host=new Host();//代理,中介帮房东租房子,代理角色一般会有附属操作Proxy proxy = new Proxy(host);//你不用面对房东,直接找中介租房即可!proxy.rent();}
}

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务!
  • 公共也就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色,代码量会饭呗,开发效率会变低!

9.2动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口----JDK动态代理
    • 基于类 :cglib
    • java字节码实现:javasist

需要了解两个类:Proxy(代理),InvocationHandler(调用处理程序)

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务!
  • 公共也就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务;
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可;

10AOP

10.1什么是AOP

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式运行期动态代理 实现程序功能的统一维护的一种技术,AOP是OOP的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑个部分之间的耦合度很低,提高程序的可重用性,同时提高了开发的效率。

10.2AOP在Spring中的作用

提供声明式事务,允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法和功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志、安全、缓存、事务等等…
  • 切面(ASPECT):横切关注点 被模块化的特殊对象,即它是一个类。
  • 通知(ACTIVE):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象;
  • 切入点(PointCut):切面通知 执行的“地点”的定义
  • 连接点(JoinPoint):与切入点匹配的执行点


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部