Spring学习笔记

本文介绍了Spring框架的核心概念和优势,包括控制反转IoC和面向切面编程AOP,以及Spring的预设知识,如BeanFactory和ApplicationContext。通过一个简单的入门程序展示了Spring的配置过程。进一步探讨了Spring的核心容器、IOC和DI的理解,强调了依赖注入的重要性。文章还涵盖了Spring中Bean的实例化、作用域和生命周期管理,并讨论了Spring配置文件的拆分、Druid连接池的使用以及如何引入外部properties文件。最后,简要提及了Spring的代理和动态代理实现。

预备知识

在这里插入图片描述

1、什么是spring

1什么是Spring
Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring 的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转( IoC )和面向切面( AOP ).简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架
Spring主要的目的:简化企业开发

2、Spring核心

Spring的核心是控制反转( loC)和面向切面(AOP )。

1.2 Spring框架的优点

  • 方便解耦,简化开发
    通过 Spring提供的loC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
  • AOP编程的支持
    通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
  • 声明式事务的支持
    在Spring 中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
  • 方便程序的测试
    可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring 对Junit4支持,可以通过注解方便的测试Spring程序。
  • 方便集成各种优秀框架
    Spring 不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz )等的直接支持。
  • 降低Java EE API的使用难度
    Spring对很多难用的Java EE API(如JDBc,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring 的简易封装,这些Java EE API的使用难度大为降低。
  • . Java源码是经典学习范例
    Spring 的源码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring 框架源码无疑是Java技术的最佳
  • 实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。

3、初识spring

这里写图片描述

Spring一共有十几个组件,但是真正的核心组件只有几个,我们一起来看下Spring框架的总体架构图,了解一下他的体系结构。
从这个图中我们可以看出Spring框架的核心组件只有三个:Core、Context和Beans。他们构建起了整个Spring的骨骼架构,没有他们就不可能有AOP、Web等上层的特性功能。上面这些是Spring特性功能。

我列举了比较重要的几个包:AOP包(主要提供面向切面编程的实现),Web(主要提供了Web应用开发的支持及针对Web应用的MVC思想实现)、ORM(为我们之前学的Hibernate,以及以后会学到的Mybatis这类持久化框架提供支持)、还有Spring MVC (这个是它自带的一个web视图层,可以替代到Sturts2,将来我们还会详细的学习这个SpringMVC框架)。。等等,其中最最核心的就是AOP和下面Spring核心包,也是我们学习的重点
1.4 Spring的两大核心技术
控制反转(IoC : lnversion of Control ) /依赖注入(DI : Dependency Injection )面向切面编程(AOP : Aspect Oriented Programming)

二、Spring入门程序

1、在pom.xml添加spring的相关依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

2、在main/resources创建beans.xml文件(spring配置文件)

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

</beans>

3、编写组件完成操作

package com.woniuxy;

public class HelloWorld {
    public String sayHello(String name){
        return "Hello"+name+"!";
    }
}

4、在Spring的配置文件中声明定义这个bean

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

<!--    如下结点相当于调用无参构造方法完成对象的实例化,HelloWorld helloworld=new HelloWorld()
        id:bean对象的唯一标识
        class:类全名
-->
    <bean id="hello" class="com.woniuxy.HelloWorld"></bean>
</beans>

5、测试

private Logger logger = Logger.getLogger(this.getClass());
@Test
public void testHelloworld()
{
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Object obj=context.getBean("hello");
    if (obj instanceof HelloWorld){
        HelloWorld hw=(HelloWorld) obj;
        logger.info(hw.sayHello("Spring "));
    }
}

三、Spring的核心容器

Spring提供了两种核心容器,分别是BeanFactory和ApplicationContext

1 、BeanFactory

BeanFactory是基础类型的STOC容器,它提供了完整的TOC服务支持,简单来说,BeanFacory就是一个管理Bean的工厂,它主要负责初始化各种Bean,并调用它们的生命周期方法

BeanFactory接口有多个实现类,最常见的是XmlBeanFactory

@Test
public void testBeanFactory(){
    BeanFactory factory = new XmlBeanFactory(new FileSystemResource("E:\\IDEA\\WN-Spring\\spring-01-quickstart\\src\\main\\resources\\beans.xml"));
    Object obj=factory.getBean("hello");
    if(obj instanceof HelloWorld){
        HelloWorld hw=(HelloWorld) obj;
        logger.info(hw.sayHello("Giles"));
    }
}

2、ApplicationContext

AppicationContext是BeanFactory的子接口,ApplicationContext不仅包含了BeanFactory的所有功能,还添加了对国际化,资源访问,事件传播等方面的支持ApplicationContext接口有两个常用的实现类,具体如下所示

. ClassPathXmlApplicationContext:该类从类路径中寻找指定的XML配置文件

. FileSystemXmlApplicationContext:该类从指定的文件系统中寻找指定的XML配置文件

在WEB项目中,, ApplicationContext容器的实例化工作会交由WEB服务器完成,WEB服务器实例化ApplicationContext容器通常使用基于ContextLoaderlistener实现的方式,它需要在web.xml中添加如下代码

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value></context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

3 BeanFactory和ApplicationContext的主要区别:

如果Bean的某一个属性没有注入,则使BeanFactory加载后,在第一次调用getBean()方法时会抛出异常
而ApplicationContext则在初始化时自检,这样有利于检
查所依赖的属性是否注入。
因此,在实际开发过程中,通常都选择使用ApplicationContext,而只有在系统资源较少时,才考虑使用BeanFactory。

四、Spring IOC和DI概念理解(重中之重)

1、IOC(控制反转)降低程序的耦合性

(1)IOC(控制翻转)控制反转(IOC )
依赖注入( Dependency Injection,简称DI )
IOC和DI是一回事,只是在不同的角度去诠释同一个问题1)控制反转(IOC )

使用Spring之前

在这里插入图片描述

使用Spring之后
在这里插入图片描述

由代码来维护程序之间的关系,有了spring容器之后,程序之间的这种关系,控制权由应用程序转移到到了Spring容器,控制器权发生了反转,这就是spring的控制反转,称为IOC

DI(依赖注入)

从另外一个角度来说明
在这里插入图片描述
所谓的依赖注入:在程序运行的过程中临时组装各组件(各组件之间要有合适的接口)

思考:是不是所有的组件都需要放在Spring容器中来管理?不是的

五、依赖注入的实现方式

有两种放心可以进行注入,setter方式(使用更多),构造方法注入

1、SET方式的注入

1)、基本数据类型的注入

简单数据类型

|–基本数据类型: byte、short、int、long、float、double、Boolean、char

|–引用数据类型String

使用value属性或者value来实现注入的

pojo实体类:

public class Student {
    private String name;
    private int age;

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

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "name:"+name+"年龄"+age;
    }
}

beans.xml配置

<!--    简单类型的注入-->
    <bean id="student1" class="com.woniuxy.pojo.Student">
        <property name="name" value="张三"></property>
        <property name="age">
            <value>18</value>
        </property>
    </bean>
<!--
        如果遇到特殊字符,XML中的解决办法有两种
        1、通过转义字符:比如:P&amp;G
        2、通过<!CDATA[]>方式来进行转义

-->
    <bean id="student2" class="com.woniuxy.pojo.Student">
        <property name="name" value="P&amp;G"></property>
        <property name="age" value="16"></property>
    </bean>

    <bean id="student3" class="com.woniuxy.pojo.Student">
        <property name="name">
            <value><![CDATA[P&G]]></value>
        </property>
        <property name="age" value="16"></property>
    </bean>

测试:

public void testDi1()
{
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Student student= (Student) context.getBean("student1");
    logger.info(student);
}

2)注入bean对象类型

package com.woniuxy.pojo;

import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
public class Dept implements Serializable{
    private byte deptno;
    private String dname;
    private String loc;
    private List<Emp> emps;
}
package com.woniuxy.pojo;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class Emp implements Serializable{
    private short empno;
    private String ename;
    private String job;
    private short mgr;
    private Date hiredate;
    private double sal;
    private double comm;
    private Dept dept;
}
package com.woniuxy.dao;

import com.woniuxy.pojo.Dept;

import java.util.List;

public interface DeptDao {
    public List<Dept> findAll();
}
package com.woniuxy.dao.impl;

import com.woniuxy.dao.DeptDao;
import com.woniuxy.pojo.Dept;
import org.apache.log4j.Logger;

import java.util.List;

public class DeptDaoImpl implements DeptDao {
    private Logger logger=Logger.getLogger(this.getClass());
    @Override
    public List<Dept> findAll() {
        logger.info("使用mybatis实现部门的查询操作");
        return null;
    }


}
package com.woniuxy.dao.impl;

import com.woniuxy.dao.DeptDao;
import com.woniuxy.pojo.Dept;
import org.apache.log4j.Logger;

import java.util.List;

public class DeptDaoJpaImpl implements DeptDao {
    private Logger logger=Logger.getLogger(this.getClass());
    @Override
    public List<Dept> findAll() {
        logger.info("使用spring data JPA实现部门的查询");
        return null;
    }
}
package com.woniuxy.service;

import com.woniuxy.pojo.Dept;

import java.util.List;

public interface DeptService {
    public List<Dept> findAllDepts();
}
package com.woniuxy.service.impl;

import com.woniuxy.dao.DeptDao;
import com.woniuxy.pojo.Dept;
import com.woniuxy.service.DeptService;

import java.util.List;

public class DeptServiceImpl implements DeptService {
    private DeptDao deptDao;

    public void setDeptDao(DeptDao deptDao) {
        this.deptDao = deptDao;
    }

    @Override
    public List<Dept> findAllDepts() {
        return deptDao.findAll();
    }
}
<!--  bean的注入  -->

    <bean id="deptDao" class="com.woniuxy.dao.impl.DeptDaoImpl"></bean>
    <bean id="deptJpaDao" class="com.woniuxy.dao.impl.DeptDaoJpaImpl"></bean>
    <bean id="deptService" class="com.woniuxy.service.impl.DeptServiceImpl">
<!--        <property name="deptDao" ref="deptJpaDao"></property>-->
        <property name="deptDao">
            <ref bean="deptJpaDao"></ref>
        </property>
    </bean>
@Test
public void testDi2()
{
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   DeptService deptService = (DeptService) context.getBean("deptService");
   deptService.findAllDepts();
}

3)注入集合类型

常用的集合 List、set、Map、Properties(主要做配置)

3.1)注入List集合

package com.woniuxy.pojo;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Person {
    private List<String> names;
    private Set<String> inserts;
    private Map<String,String> wifes;
    private Properties jobs;

    public void setJobs(Properties jobs) {
        this.jobs = jobs;
    }

    public void setWifes(Map<String, String> wifes) {
        this.wifes = wifes;
    }

    public void setInserts(Set<String> inserts) {
        this.inserts = inserts;
    }

    public void setNames(List<String> names) {
        this.names = names;
    }

    @Override
    public String toString() {
        return "Person{" +
                "names=" + names +
                ", inserts=" + inserts +
                ", wifes=" + wifes +
                ", jobs=" + jobs +
                '}';
    }
}
<!--注入List集合-->
<bean id="person" class="com.woniuxy.pojo.Person">
    <property name="names">
        <list>
            <value>张三</value>
            <value>李四</value>
        </list>
    </property>
    <property name="inserts">
        <set>
            <value>AAAA</value>
            <value>BBBB</value>
        </set>
    </property>
    <property name="wifes">
        <map>
            <entry key="first">
                <value>CCCC</value>
            </entry>
            <entry key="sec">
                <value>DDDD</value>
            </entry>
        </map>
    </property>
<property name="jobs">
    <props>
        <prop key="1">EEEEE</prop>
        <prop key="2">FFFFF</prop>
    </props>
</property>
</bean>
@Test
public void testDi3()
{
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   Person person = (Person) context.getBean("person");
    logger.info(person);
}
@Test
public void testProperties(){
    Properties pro=new Properties();
    InputStream in = this.getClass().getClassLoader().getResourceAsStream("datasource.properties");
    try {
        pro.load(in);
        logger.info(pro.getProperty("driver"));
        logger.info(pro.getProperty("url"));
        logger.info(pro.getProperty("username"));
        logger.info(pro.getProperty("password"));

    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Test
public void testProperties2(){
    Properties pro=new Properties();
    pro.setProperty("driver","com.mysql.jdbc.Driver");
    pro.setProperty("url","jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF8");
    pro.setProperty("username","root");
    pro.setProperty("password","123456");
    OutputStream os= null;
    try {
        os = new FileOutputStream("E:\\IDEA\\WN-Spring\\spring-02-di\\src\\main\\resources\\datasource.properties");
        pro.store(os,"datasource.properties");
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        try {
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

4)构造子注入注入(构造方法注入)

package com.woniuxy.pojo;

public class Teacher {
    private String name;
    private Integer lessionAge;
    private Double score;
    private String school;

    public Teacher(String name, Integer lessionAge, Double score) {
        this.name = name;
        this.lessionAge = lessionAge;
        this.score = score;
    }

    public Teacher(String name, Integer lessionAge, Double score, String school) {
        this.name = name;
        this.lessionAge = lessionAge;
        this.score = score;
        this.school = school;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", lessionAge=" + lessionAge +
                ", score=" + score +
                ", school='" + school + '\'' +
                '}';
    }
}
<!--    构造方法注入-->
    <bean id="teacher" class="com.woniuxy.pojo.Teacher">
        <constructor-arg index="0" value="刘老师"></constructor-arg>
        <constructor-arg index="1" value="12"></constructor-arg>
        <constructor-arg index="2" value="10"></constructor-arg>
    </bean>

    <bean id="teacher2" class="com.woniuxy.pojo.Teacher">
        <constructor-arg name="name" value="张三"></constructor-arg>
        <constructor-arg name="lessionAge" value="11"></constructor-arg>
        <constructor-arg name="score" value="12"></constructor-arg>
    </bean>
<!--    使用这种类型,必须在实体对象中使用包装类型,而且有多个同类型,还要注意顺序-->
    <bean id="teacher3" class="com.woniuxy.pojo.Teacher">
        <constructor-arg type="java.lang.String" value="李四"></constructor-arg>
        <constructor-arg type="java.lang.Integer" value="13"></constructor-arg>
        <constructor-arg type="java.lang.Double" value="15"></constructor-arg>
        <constructor-arg type="java.lang.String" value="嘻嘻嘻嘻嘻嘻"></constructor-arg>
    </bean>
@Test
public void testDi5(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Teacher teacher = (Teacher) context.getBean("teacher");
    logger.info(teacher);
}
@Test
public void testDi52(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Teacher teacher = (Teacher) context.getBean("teacher2");
    logger.info(teacher);
}
@Test
public void testDi53(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Teacher teacher = (Teacher) context.getBean("teacher3");
    logger.info(teacher);
}

5) P命令空间注入(了解)

xmlns:p="http://www.springframework.org/schema/p"  //在bean的顶部加入
<!--    P命名空间注入-->
    <bean id="student4" class="com.woniuxy.pojo.Student" p:name="王小明" p:age="23"></bean>
</beans>
@Test
public void testStudent4(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Student student = (Student) context.getBean("student4");
    logger.info(student);
}

6)自动装配(了解)

使用xm进行注入的时,大家会发现配置文件的内容越来越多,XMNL的可读性不是很高,而且XML中配置内容过多也是一份工作量,开始想办法去减少配置,自动配置就可以减少配置。
要使用自动装配,就需要配置元素的autowire属性。autowire属性有五个值,具体说明如下。

取值说明
(1)no默认值。Spring默认不进行自动装配,必须显式指定依赖对象
(2)byName根据属性名白动装配。Spring自动查找与属性名相同的id,如果找到,则白动注入,否则什么都不做根据属性的类型白动装配。Spring自动查找与屈性类型相同的Bean,
(3)by Type如果刚好找到唯一的那个,则白动注入;如果找到多个与屁性类型相同的Bean,则抛出异常;如果没找到,就什么也不做
(4)constructor和byType类似,不过它针对构造方法。如果Spring找到一个Bean和构造方法的参数类型相匹配,则通过构造注入该依赖对象;如果找不到,将抛出异常
<bean id="deptService" class="com.woniuxy.service.impl.DeptServiceImpl">   <!--        autowire="byName"-->
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">

7)使用注解完成自动装配(重点掌握)

在之前已经XML配置了,使用大量的XML配置,使得整个项目变得非常的臃肿,Spring主要的目标是简化企业开发,提高开发效率,学习框架以后,没减轻工作量,反而工作量变大,有着大量的XML配置,XML配置的年代过度到注解配置的时代,XML的配置依然存在,主要是以注解为主,XML为辅
在使用注解之前必须要在spring的配置文件中配置扫描注解的位置,否则虽然已经在类的前面添加@Component,但是spring配置文件,并没有找到这个位置.

@Component:所有的组件都可以使用这个注解
@Component就相当于在spring配置文件中完成的声明,就相当于是实例化对象

类型唯一:
package com.woniuxy.dao;

import java.util.List;

public interface IDeptDao {
    public List findAll();

}
package com.woniuxy.dao.impl;

import com.woniuxy.dao.IDeptDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import java.util.List;
@Component
/*
*   @Component的作用就相当于在Spring 的配置文件中声明了bean
* <bean id="deptDaoImpl" class="com.woniuxy.dao.DeptDaoImpl" />  id值,class类型首字母小写
* 注意:如果这个@Component要被Spring容器所识别,别需要在扫描的包下
* */
public class DeptDaoImpl implements IDeptDao {
    private Logger logger=Logger.getLogger(this.getClass());
    @Override
    public List findAll() {
        logger.info("使用mybatis查询所有的部门信息");
        return null;
    }
}
package com.woniuxy.service;

import java.util.List;

public interface IDeptService {

    public List findAllDept();

}
package com.woniuxy.service.impl;

import com.woniuxy.dao.IDeptDao;
import com.woniuxy.service.IDeptService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
@Component
public class DeptServiceImpl implements IDeptService {
    @Resource//依赖注解
    /*@Resource 首先按照名称进行自动装配,如果名称对应不上,则按照类型进行自动装配
     *
     * **/
private IDeptDao iDeptDao;

    @Override
    public List findAllDept() {
        return iDeptDao.findAll();
    }
}

测试

@Test
public void test()
{
    ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
    IDeptService deptService =(IDeptService) context.getBean("deptServiceImpl");
    deptService.findAllDept();


}
类型不唯一:@Resource
package com.woniuxy.dao.impl;

import com.woniuxy.dao.IDeptDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import java.util.List;
@Component("deptDaoJpa")
public class DeptDaoJpaImpl implements IDeptDao {
    private Logger logger=Logger.getLogger(this.getClass());
    @Override
    public List findAll() {
        logger.info("使用Spring Data JPA查询所有的部门信息");
        return null;
    }
}
package com.woniuxy.service.impl;

import com.woniuxy.dao.IDeptDao;
import com.woniuxy.service.IDeptService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
@Component
public class DeptServiceImpl implements IDeptService {
    @Resource(name = "deptDaoJpa")
    //依赖注解
    /*@Resource 首先按照名称进行自动装配,如果名称对应不上,则按照类型进行自动装配
     *
     * **/
private IDeptDao iDeptDao;

    @Override
    public List findAllDept() {
        return iDeptDao.findAll();
    }
}
类型不唯一:@autowired @Qualifier
package com.woniuxy.dao.impl;

import com.woniuxy.dao.IDeptDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import java.util.List;
@Component("deptDaoMybatis")
/*
*   @Component的作用就相当于在Spring 的配置文件中声明了bean
* <bean id="deptDaoImpl" class="com.woniuxy.dao.DeptDaoImpl" />  id值,class类型首字母小写
* 注意:如果这个@Component要被Spring容器所识别,别需要在扫描的包下
* */
public class DeptDaoImpl implements IDeptDao {
    private Logger logger=Logger.getLogger(this.getClass());
    @Override
    public List findAll() {
        logger.info("使用mybatis查询所有的部门信息");
        return null;
    }
}
package com.woniuxy.dao.impl;

import com.woniuxy.dao.IDeptDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import java.util.List;
@Component("deptDaoJpa")
public class DeptDaoJpaImpl implements IDeptDao {
    private Logger logger=Logger.getLogger(this.getClass());
    @Override
    public List findAll() {
        logger.info("使用Spring Data JPA查询所有的部门信息");
        return null;
    }
}
package com.woniuxy.service.impl;

import com.woniuxy.dao.IDeptDao;
import com.woniuxy.service.IDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
@Component
public class DeptServiceImpl implements IDeptService {
    //@Resource(name = "deptDaoJpa")
    //依赖注解
    /*@Resource 首先按照名称进行自动装配,如果名称对应不上,则按照类型进行自动装配
     *
     * **/
    @Autowired //首先按类型匹配,如果类型一样则可以匹配成功
    @Qualifier("deptDaoMybatis")//在qualifier协商需要匹配的类型的名字,与autowired组合使用
    //如果自动装配的过程中发现,同一类型的对象有多个,则需要结合@Qualifier来指定要装配的对象的名称,方能唯一的装配
private IDeptDao iDeptDao;

    @Override
    public List findAllDept() {
        return iDeptDao.findAll();
    }
}
其他注解

如果上所有的组件都是用的@Component ,但是在实际开发过程中使用@Compent,虽然也能完成Bean实例化声明,但是不能见名知意,Spring提供了如下注解

Repository:用于声明DAO层的

service:用于业务层

Controller:用于控制器

关于扫描包的问题

context:exclude-filter排除扫描哪个注解

context:include-filter :只扫描哪个注解

六、Spring中的bean

1、实例化bean(了解)

Spring bean有三种方式

1、构造方式方法的方式(最常用)

<bean id="student1" class="com.woniuxy.pojo.Student">
    <property name="name" value="张三"></property>
    <property name="age">
        <value>18</value>
    </property>
</bean>

2、静态工厂的方式

public class MyFactory {
public static Person createPerson(){
return new Person();
}
<!--
静态工厂方式创建bean对象class:工厂的类全名
factory-method:静态工厂方法-->
<bean id="person" class="com.woniuxy.factory.MyFactory" factory-method="createPerson"></bean>

3、实例工厂方式

package com.woniuxy.factory;

import com.woniuxy.pojo.Person;

public class PersonFactoryInstance {
    public Person createPerson(){
        return new Person();
    }
}
<bean id="personFactoryInstane" class="com.woniuxy.factory.PersonFactoryInstance"></bean>
    <bean id="person2" class="com.woniuxy.pojo.Person" factory-bean="personFactoryInstane" factory-method="createPerson"></bean>
@Test
public void testFacory2()
{
    ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
    Person person =(Person)context.getBean("person2");
    logger.info(person);
}

2、bean的作用域(理解)

spring中为bean的实例定义了7种作用域,这7种作用域说明如下表所示在bean节点中通过scope属性来设置bean的作用域

作用域说明
singleton默认值。Spring以单例模式创建Bean的实例,即容器中该Bean的实例只有一个
prototype每次从容器中获取Bean时,都会创建一个新的实例
request用于Web应用环境,针对每次HTTP请求都会创建一个实例
session用于Web应用环境,同一个会话共享同一个实例,不同的会话使用不同的实例
global session仅在Portlet的Web应用中使用,同一个全局会话共享一个实例。对于非Portlet环境,等同于session

7种作用域种singleton和prototype最常用的两种

2.1 singleton作用域
2.2 prototype作用域

3、Bean生命周期[理解]

1、什么bean的生命周期

通过new的方式创建一个对象,从创建到销毁过程称为这个bean的生命周期

spring中bean的生命周期是什么样子呢?

从创建到销毁的过程 两种作用域的生命周期是不一样的
案例

<!--
在spring的bean节点中通过
	init-method:初始化方法
	destory-method:销毁方法
1)如果scope为singleton,如果单例,实际上初始化spring容器的时候调用
销毁方法是在spring容器销毁的时候会被调用,实际上单例的对象和spring容器的生命周期是一样的

bean:实例化初始化销毁容器:实例化销毁
2)如果是scope为多例,bean的生命周期,实际上每次调用getBean()开始创建对象,容器即便销毁了,对象的销毁方法也不会执行实例化(getBean())初始化通过程序销毁
-->

Spring容器可以管理singleton作用域Bean的生命周期,在此作用域下,Spring能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁。而对于
prototype作用域的Bean , Spring只负责创建,当容器创建了Bean的实例后,Bean的实例就交给客户端代码管理,Spring容器将不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring容器都会创建一个新的实例,并且不会管那些被配置成prototype作用域的Bean的生命周期。
了解Spring生命周期的意义就在于,可以利用Bean在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在Bean被初始化后和被销毁前执行一些相关操作。
在Spring中 , Bean的生命周期是一个很复杂的执行过程,我们门可以利用Spring提供的方法定制Bean的创建过程。当一个Bean被加载到Spring容器时,它就具有了生命,而Spring容器在保证一个Bean能够使用之前,会进行很多工作。Spring容器中Bean的生命周期流程

    <!--
    实例化bean的三种方式
    1、通过构造方法来构造
    2、通过静态工厂来创建
        如下属性的含义
        |-class :静态工厂的类全名
        |-factory-method:工厂类中的静态方法
        3、通过实例工厂创建
    -->
<bean id="person1" class="com.woniuxy.factory.PersonFactory" factory-method="createPerson" scope="prototype"></bean>

<bean id="personFactoryInstane" class="com.woniuxy.factory.PersonFactoryInstance"></bean>
    <bean id="person2" class="com.woniuxy.pojo.Person" factory-bean="personFactoryInstane" factory-method="createPerson"  scope="prototype"></bean>
    <!--bean的作用域,通过scope属性来指定,指定的有两个,默认值的是sigleton单例,prototype:多例-->
    <bean id="date" class="java.util.Date" scope="prototype"></bean>
    <!--bean的生命周期 -->
    <bean id="person3" class="com.woniuxy.pojo.Person" init-method="init" destroy-method="destory" scope="singleton">
        <property name="name" value="张无忌"></property>
        <property name="age" value="21"> </property>
    </bean>

单例对象------在spring容器创建的时候实例化

多例对象------在调用getBean的时候采取实例化

单例对象------->当spring容器销毁的时候他也销毁

多例对象------->容器销毁不会调用destroy-method-------多例的销毁由自己来

Spring容器可以管理singleton作用域Bean的生命周期,在此作用域下,Spring能够特确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁。而对于prototype作用域的Bean , spring只负责创建,当容器创建了Bean的实例后,Bean的实例就交给客户端代码管理,Spring容器将不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring容器都会创建一个新的实例,并且不会管那些被配置成prototype作用域的Bean的生命周期。

了解Spring生命周期的意义就在于,可以利用Bean在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在Bean被初始化后和被销毁前执行一些相关操作。
在Spring中, Bean的生命周期是一个很复杂的执行过程,我和们可以利用Spring提供的方法定制Bean的创建过程。当一个Bean被加载到Spring容器时,它就具有了生命,而Spring容器在保证一个Bean能够使用之前,会进行很多工作。Spring容器中Bean的生命周期流程

在这里插入图片描述

Bean生命周期的整个执行过程描述如下。
(1)根据配置情况调用Bean构造方法或工厂方法实例化Bean。

(2)利用依赖注入完成Bean中所有属性值的配置注入。

( 3 )如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的lid值。

(4)如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用。
(5 )如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用。
(6)如果BeanPostProcessor和Bean关联,则Spring将调用该接口的预初始化方法postProcessBeforeiIntialzation()对SBean进行加工操作,此处非常重要,Spring的AOP就是利用它实现的
(7)如果Bean实现了InitializingBean接口,则Spring将调用afterPropertiesSet()方法。

(8)如果在配置文件中通过init-method属性指定了初始化方法,则调用该初始化方法。
(9)如果BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化方法postProcessAfternitialization()。此时,Bean已经可以被应用系统使用了。
(10 )如果在中指定了该Bean的作用范围为scope=“singleton”,则将该Bean放入Spring IoC的缓存池中,将触发Spring对该Bean的生命周期管理;如果在中指定了该Bean的作用范围为scope="prototyp e”;则将该Bean交给调用者,调用者管理该Bean的生命周期,Sprinq不再管理该Bean

(11)如果Bean实现了DisposableBean接口,则Spring会调用destory()方法将Spring中的Bean销毁
如果在配置文件中通过destory-method属性指定了Bean的销毁方法,则Spring将调用该方法对Bean进行销毁。
Spring为Bean提供了细致全面的生命周期过程,通过实现特定的接口或的属性设置,都可以对Bean的生命周期过程产生影响。虽然可以随意配置的属性,但是建议不要过多地使用Bean实现接口,因为这样会导致代码和Spring的聚合过于紧密

4、spring配置文件的拆分【掌握】

在企业中随着项目内容不断增加,同时配置信息越来越多,把所有的配置信息放在同一个配置文件,把着这个配置文件就会变得越来越臃肿,可读性也会降低,查询配置信息,具体拆分的策略,由项目具体而定

<?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.orK/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd""><import resource="beans-first.xml"></import>
<import resource="beans-second.xml"></import>
<import resource="beans-third.xml"></import>
<import resource="beans-fourth.xml"></import>
</beans>
<xml version="1.o" encoding="UTF-8"?>
<beans xmlns="http: // www.springframework.orglschema/beans"
xmlns:xsi="http: / /www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation="http:// www. springframework. orglschema/beans
                   http: //www.springframework.org/schema/beans/spring -beans.xsd">
<import resource="bean1.xml"/import>
<import resource="bean2.xml"></import>
<import resource="beans xml"></import>
</beans>

5、DRUID连接池【掌握】

常用连接池技术:DBCP、C3PO、Proxool、Druid

1 )在pom.xml文件中添加组件依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.22</version>
</dependency>

2)代码

<bean id="dataSources" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=UTF8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
        <!--数据连接池初始化数-->
        <property name="initialSize" value="15"></property>
<!--        最小连接池数量-->
        <property name="minIdle" value="5"/>
        <!--最大连接数据库连接数-->
        <property name="maxActive" value="100"/>
        <!--最大等待毫秒数-->
        <property name="maxWait" value="6000"/>

    </bean>

测试

@Test
public void testDataSource() throws SQLException {
    ApplicationContext context= new ClassPathXmlApplicationContext("beans.xml");
    DruidDataSource dataSource = (DruidDataSource) context.getBean("dataSources");
    logger.info(dataSource.getConnection());
}

6、spring引入外部的properties文件

在spring中引入外部的properties文件的方法有两种

在resources目录下新建datasource.properties文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=UTF8
user=root
password=123456
initialSize=10
minIdle=5
maxActive=100
maxWait=6000

(1)使用PropertyPlaceholderConfigurer引入(不推荐使用)

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="datasource.properties"/>

    </bean>
    <bean id="dataSources" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <!--数据连接池初始化数-->
        <property name="initialSize" value="${initialSize}"></property>
<!--        最小连接池数量-->
        <property name="minIdle" value="${minIdle}"/>
        <!--最大连接数据库连接数-->
        <property name="maxActive" value="${maxActive}"/>
        <!--最大等待毫秒数-->
        <property name="maxWait" value="${maxWait}"/>

    </bean>

2)使用context:property-placeholder引入

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


    <context:property-placeholder location="datasource.properties"/>
    <bean id="dataSources" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <!--数据连接池初始化数-->
        <property name="initialSize" value="${initialSize}"></property>
<!--        最小连接池数量-->
        <property name="minIdle" value="${minIdle}"/>
        <!--最大连接数据库连接数-->
        <property name="maxActive" value="${maxActive}"/>
        <!--最大等待毫秒数-->
        <property name="maxWait" value="${maxWait}"/>

    </bean>
</beans>

使用qontext:property-placeholder的时候出现引用不来情况
原因是∶由于properties内username和系统环境的username重名导致的,解决办法有两种
第1种∶不要在配置文件中出现username这样的key,重新取个名称,一般有一个习惯给前面带jdbc前缀例如

jdbc. driver=com.aysql.jdbc. Driver
jdbc.url=jdbc:nysql://localhost:3306/nybatis?useUnicode=truekcharacterEncoding-utf8
jdbc.usernane=root
jdbc. password=1234

第2种∶在property-placeholder>中加入system-properties-mode="FALLBACK”也可以解决这个问题

七、SpringAOP

—.代理
**代理分为:**静态代理 、动态代理
代理模式∶目标对象,增强部分的内容

**什么是代理:**代理模式 ( Proxy )是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。

在这里插入图片描述

1.静态代理的实现

2.动态代理的实现
JDK的动态代理,使用了Proxy中的静态方法newProxyInstance,该方法有三个参数
· ClassLoader loader:目标对象的类加载器

### 关于Spring框架的学习教程和笔记 #### Spring框架的核心概念与组件介绍 Spring是一个分层架构,通过使用基本的Java Bean来完成以前只有EJB才能实现的功能。它提供了对面向切面编程的支持,允许用户定义方法拦截器,在特定的方法调用前后执行通知逻辑[^1]。 #### Web开发中的Spring应用实例 对于Web应用程序而言,`spring-web-5.3.24.jar` 和 `spring-webmvc-5.3.24.jar` 是必不可少的部分。前者提供了一个全面的、易于使用的HTTP请求处理机制;后者则实现了MVC设计模式下的控制器接口,使得开发者可以更方便地构建动态网站。 #### 使用Maven搭建Spring项目实践指南 当采用Maven作为项目的构建工具时,可以通过编辑POM文件快速引入所需的库文件。例如,为了开启web场景支持,只需简单添加如下依赖项即可: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 这段XML片段会自动下载并配置好所有必要的jar包,从而简化了环境设置过程[^3]。 #### 配置服务发现与外部化配置管理方案 针对分布式系统的复杂需求,还可以考虑集成Consul来进行服务注册和服务发现工作,并利用Bootstrap上下文提前加载全局共享属性。这通常涉及到向pom.xml中追加额外的服务端点连接信息: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> ``` 上述代码段有助于提高微服务体系结构下各节点之间的协作效率[^4]。 #### 数据验证功能的具体实施方式 最后,在实际编码过程中如果遇到表单提交等涉及输入合法性判断的情况,则可借助Hibernate Validator API轻松搞定。创建一个名为ValidationConfig.java的新类用于初始化默认校验工厂对象LocalValidatorFactoryBean: ```java @Configuration @ComponentScan("com.atguigu.spring6.validation.method2") public class ValidationConfig { @Bean public LocalValidatorFactoryBean validator() { return new LocalValidatorFactoryBean(); } } ``` 此段程序展示了如何自定义配置以增强业务逻辑层面的数据完整性保护措施[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值