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配置
<!--    id:bean的唯一标识符,也就是相当于我们学的对象名
        class:bean对象所对应的全限定名:包名+类名
        name:也是别名 ,而用Name可以取多个别名-->
    <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

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--    第一种,普通值注入,value-->
        <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>LOL</value>                <value>BOB</value>                <value>COC</value>            </set>        </property>        <property name="wife">            <null />        </property>        <property name="info">            <props>                <prop key="学号">137264</prop>                <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/

    <?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">
        <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;
        @Resource
        private 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;
        }
        @Override
        public 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属性
        @Bean
        public 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):与切入点匹配的执行点
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值