Spring框架核心机制IOC和AOP深入解读spring基础

Spring框架核心机制IOC和AOP深入解读spring基础,第1张

1. Spring框架 1.1 Spring简介
  • Spring就是分层的JavaSE应用full-strack轻量级开源框架,IOC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)
  • 什么是轻量级?一般情况下如果框架api使用比较简单,就叫轻量级
1.2 Spring的架构组成
1.2.1 Spring框架

最重要的核心容器Core Container:分为4个部分

  • Beans ,容器主要放的就是定义的bean对象
  • Core,核心
  • Context,上下文
  • SpEL,就是Spring的EL表达式
1.2.2 工厂
  1. CoreContariner核心容器,其实是搭建并管理了工厂
  2. 是工厂的设计模式
  3. 工厂中是用来生产项目中一个一个的对象
  4. 因此使用spring最重要的就是搭建工厂
  5. 该工厂加载配置文件:.xml文件,生产配置中记录的对象,我们通过getBean方法调用就可以了
1.3 控制反转
1.3.1 例题讲解

什么是反转控制? 反转了依赖关系的满足方式,由之前的直接创建依赖对象,变为由工厂推送。(变主动为被动,即反转)解决了具有依赖关系的组件之间的强耦合

举例说明

  • 比如UserServiceImpl强耦合了UserDaoImpl,利用了反转控制,可以使UserServiceImpl不再引用任何一个UserDao的实现类例如UserDaoImpl,在需要UserDaoImpl的位置,我们只给一个属性UserDao userDao;并定义set/get方法,允许userDao属性接收spring赋值
public class UserServiceImpl implements UserService{

	private UserDao userDao;
    @Override
    public List<User> queryUser() {
    	userDao.queryUser();
        return list;
    }
    public UserDao getUserDao(){
    	return UserDao;
    }
    public void setUserDao(UserDao userDao){
    	this.userDao = userDao;
    }
}
1.3.2 先写一个spring-context.xml文件
  • 上面我们说过了,反转控制,那么spring是怎么给UserServiceImpl类的UserDao属性赋值的呢?假设我们赋值的是UserDao的实现类UserDaoImpl
  • 首先,我们在.xml配置文件中定义一个标签,里面写
  • 标签的id随便给,id=“userDaoImpl”、class=”com/lyx/dao/impl/UserDaoImpl“,就是UserDaoImpl的路径

1.3.3 controller层

Control层调用Sevice层的时候,如下调用

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
        UserDaoImpl userDao = (UserDaoImpl)context.getBean("userDaoImpl");
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        userService.queryPerson();

运行结果:这里成功调用了UserDaoImpl;

理解说明

  • Spring框架加载这个.xml配置文件,
  • 怎么加载?ClassPathXmlApplicationContext类加载
 ApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
  • ClassPathXmlApplicationContext 是ApplicationContext接口的实现类,它是从类的根路径下加载配置文件

  • ApplicationContext接口,它代表应用上下文,可以通过它的实例获得Spring容器中的Bean对象

  • 我们通过.getBean(”userDaoImpl“)生产对象

  • getBean()方法的参数给bean的id,返回的就是UserDaoImpl类型的对象,类型自己强转就行了

//Object userDaoImpl = context.getBean("userDaoImpl");
UserDaoImpl userDaoImpl = (UserDaoImpl)context.getBean("userDaoImpl");
  • getBean方法的参数也可以是Class类型,这样就不需要强转了,因为你已经告诉它了,但是这种方法只适合只有一个UserDaoImpl,如果还有一个会报错
UserDaoImpl userDaoImpl = context.getBean(UserDaoImpl.class);
  • 当然了,实现功能要先导Spring开发的基本包的坐标:Spring框架用到依赖
  • 还有一点,.xml在项目加载的时候不会被编译到target测试文件里面,需要在pom.xml里面配置一个
  <build>
        <resources>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>*.xmlinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>
1.3.4 .xml配置文件的bean标签
    <bean id="" class="" scope="" init-method="" destroy-method=""/>

id、class上面说过了
scope

  1. singleton单例
  2. prototype多例

init-method

  1. 在class定义的包.类里面定义的初始化方法

destroy-method

  1. 在class定义的包.类里面定义的销毁方法,
  2. 后台自动执行销毁方法,要手动.close才能看见销毁方法有没有执行
        ApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
        Object userDao = context.getBean("userDao");
        ((ClassPathXmlApplicationContext)context).close();//强转为ApplicationContext子类
2. Spring配置文件 2.1 依赖注入之Set注入
  • 在Spring创建对象的同时,为其属性赋值,我们称为依赖注入
  • 上面讲解反转控制的时候我们在UserServiceImpl中定义了userDao属性的get/set方法,
public class UserServiceImpl implements UserService{

	private UserDao userDao;
    @Override
    public List<User> queryUser() {
    	userDao.queryUser();
        return list;
    }
    public UserDao getUserDao(){
    	return UserDao;
    }
    public void setUserDao(UserDao userDao){
    	this.userDao = userDao;
    }
}
  • 在调用userServiceImpl的时候我们是getBean返回了userDao,并通过set方法赋值给userServiceImpl的userDao属性,才成功调用
public class Controller{
	public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
        UserDaoImpl userDao = (UserDaoImpl)context.getBean("userDaoImpl");
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        userService.queryPerson();
	}
}
  • 现在来用依赖注入
  • 直接getBean返回userServiceImpl对象
  • 我们在.xml文件中创建userServiceImpl对象的bean同时,为其属性userDao赋值
  • 配置在一个标签中
  • 这就是依赖注入

<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"
>
                           
    <bean id="userDaoImpl" class="com.lyx.dao.impl.userDaoImpl">bean>
    <bean id="userServiceImpl" class="com.lyx.service.impl.userServiceImpl">
        <property name="userDao" ref="userDaoImpl">property>
    bean>
 beans>

  • 以后直接如下代码调用ServiceImpl类的方法
public class Controller{
	public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
        UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("userServiceImpl");
        userServiceImpl.queryPerson();
	}
}
  • 对比一下之前的
public class Controller{
	public static void main(String[] args){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
        UserDaoImpl userDao = (UserDaoImpl)context.getBean("userDaoImpl");
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        userService.queryPerson();
	}
}
  • 以上代码在UserServiceImpl类中没有强耦合,我们把它所有要用到的对象,如userDaoImpl,都放到了容器中,spring搭建并管理工厂,工厂加载配置文件.xml文件,生产配置文件中记录的Bean对象

以上依赖注入中的property标签也可以简化

   <?xml version="1.0" encoding="utf8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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
                           http://www.springframework.org/schema/p
                           http://www.springframework.org/schema/p/spring-p.xsd"
>
    <bean id="userDao" class="com.lyx.dao.impl.userDaoImpl"></bean>
    <bean id="userService" class="com.lyx.service.impl.userServiceImpl" p:userDao-ref="userDao"></bean>

</beans>

2.2 依赖注入之构造注入

和以上差不多,只不过property标签换成了constructor-arg标签 该标签的name值为你当前bean的class值中类的构造方法的参数类型,ref的值就是的id值

   
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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
                           http://www.springframework.org/schema/p
                           http://www.springframework.org/schema/p/spring-p.xsd"
>
    <bean id="userDao" class="com.lyx.dao.impl.userDaoImpl">bean>
    //set注入:2中方式
    //方式1
    <bean id="userService" class="com.lyx.service.impl.userServiceImpl" p:userDao-ref="userDao">bean>
    //方式2
    <bean id="userServiceImpl" class="com.lyx.service.impl.userServiceImpl">
        <property name="userDao" ref="userDaoImpl">property>
    bean>
    
    //构造注入
    <bean id="userService" class="com.lyx.service.impl.userServiceImpl">
        <constructor-arg name="userDao" ref="userDao">constructor-arg>
    bean>

beans>

当然了,UserServiceImpl类中要有构造方法

 public userServiceImpl(userDaoImpl userDao) {
}
2.3 依赖注入之注入数据类型,set注入
  • 以上注入都是把Dao注入给Service
  • 除了对象的引用可以注入,普通数据类型,集合等到可以在容器中注入
  • 比如Person类中的属性如下,有jdk8种数据类型,数组,集合,自建的Address类 ,有构造方法
  • 注入实现如下

2.3.1 Person类
public class Address {
    private int id;
    private String city;
    
    public int getId() {return id; }
    public void setId(int id) {this.id = id;}
    public String getCity() {return city;}
    public void setCity(String city) { this.city = city;}
}

package com.lyx.entity;

import com.sun.xml.internal.ws.wsdl.writer.document.http.Address;

import javax.swing.*;
import javax.xml.ws.soap.Addressing;
import java.util.*;

public class Person {
    //基本数据类型
    private int id;
    private String name;
    private Date bornDate;
    //数组
    private String[] hobbys;
    //集合
    private Set<String> phones;
    private List<String> names;
    private Map<String,String> contries;
    //文件
    private Properties files;
    //自建类型
    private Address address;

    public int getId() { return id; }

    public void setId(int id) {this.id = id;}

    public String getName() {return name;}

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

    public Date getBornDate() {return bornDate;}

    public void setBornDate(Date bornDate) {this.bornDate = bornDate;}

    public String[] getHobbys() {return hobbys;}

    public void setHobbys(String[] hobbys) {this.hobbys = hobbys;}

    public Set<String> getPhones() {return phones;}

    public void setPhones(Set<String> phones) {this.phones = phones;}

    public List<String> getNames() {return names; }

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

    public Map<String, String> getContries() { return contries;}

    public void setContries(Map<String, String> contries) {this.contries = contries;}

    public Properties getFiles() {return files;}

    public void setFiles(Properties files) {this.files = files;}

    public Address getAddress() {return address;}

    public void setAddress(Address address) {this.address = address;}

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", bornDate=" + bornDate +
                ", hobbys=" + Arrays.toString(hobbys) +
                ", phones=" + phones +
                ", names=" + names +
                ", contries=" + contries +
                ", files=" + files +
                ", address=" + address +
                '}';
    }
}

2.3.2 person-context.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/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd"
>
    <bean id="address" class="com.lyx.entity.Address">
        <property name="id" value="1">property>
        <property name="city" value="China">property>
    bean>
	<bean name="person" class="com.lyx.entity.Person">

    <property name="id" value="1">property>
    <property name="name" value="liuyuxin">property>
    <property name="bornDate" value="2020/12/12 12:20:30">property>
    
    <property name="hobbys">
        <array>
            <value>footballvalue>
            <value>basketballvalue>
        array>
    property>
    
    <property name="phones">
        <set>
            <value>111value>
            <value>222value>
        set>
    property>
    <property name="names">
        <list>
            <value>tomvalue>
            <value>jackvalue>
        list>
    property>
    <property name="contries">
        <map>
            <entry key="zg" value="china">entry>
            <entry key="els" value="russia">entry>
        map>
    property>
    <property name="files">
        <props>
            <prop key="url">jdbc:mysql:xxxprop>
            <prop key="username">rootprop>
        props>
    property>
    
    <property name="address" ref="address">property>
	bean>
beans>
2.4 引入其他配置文件


<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"
>
    <import resource="applicationContext-product.xml"/>
    <import resource="applicationContext-user.xml"/>
beans>
3. Spring配置数据源
  • 连接池可以用C3P0、我用的是Druid

jdbc.properties

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3308/companydb?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
jdbc.init=1
jdbc.minIdle=1
jdbc.maxActive=20

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
                           http://www.springframework.org/schema/p
                           http://www.springframework.org/schema/p/spring-p.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd "
>
    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="${jdbc.init}"/>
        <property name="maxWait" value="60000"/>
        <property name="timeBetweenEvictionRunsMillis" value="50000"/>
        <property name="minEvictableIdleTimeMillis" value="3000"/>
    bean>
   
beans>
4. Spring注解开发
4.1 原始注解

注解开发主要是代替的配置,对于我们注解的类或者属性,.xml文件配置一个组件扫描,spring把注解了的类自动放入容器中


注解说明
@Component
@Autowired和@Qualifier(”“)
@Repository
@Value
@Scope(“”)
@PostConstruct
@PreDestroy
4.1.1注解说明

Dao和Service的bean配置原始代码如下

    <bean id="userDaoImpl" class="com.lyx.dao.impl.userDaoImpl">bean>
    <bean id="userServiceImpl" class="com.lyx.service.impl.userServiceImpl">
        <property name="userDao" ref="userDaoImpl">property>
    bean>
  • 对于上面DaoImpl的配置,用注解代替,直接到bean的class的包的类下面,也就是这个userDaoImpl类,添加一个@Component(”“),里面的参数就是上面bean的id
  • ServiceImpl的配置,同上,但因为有依赖注入,我们还要用@Autowired和@Qualifier(”“),Qualifier里面参数是上面ref的值
  • 注解加完了,在.xml文件配置组件扫描
  • com.lyx是扫描这个路径下面所有的包
  • 注意这里用到了context,记得在beans属性里面加.xsd路径

  • 以下是完整代码
@Component("userDaoImpl")
public class UserDaoImple implements UserDao{
	@Override
	public List<User> queryUsers(){
		sql语句和queryRunner.query(sql)
	}
}
@Component("userServiceImpl")
public class UserServiceImpl implements UserService{
	@Autowired
	@Qualifier("userDaoImpl")
	private UserDao userDao;
	public void setUserDao(UserDao userDao){
		this.userDao = userDao;
	}
	public List<User> queryUsers(){
		userDao.queryUsers();
	}
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
                           http://www.springframework.org/schema/p
                           http://www.springframework.org/schema/p/spring-p.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd "
>
   
   <context:component-scan base-package="com.lyx"/>
beans>

其他注解如下


  1. 对于以上的@Component,不方便区分dao层还是Service层亦或者是Controller层
  2. 所以对于本来要使用@Component的位置,我们在Dao层用@Repository,在Service层用@Service,在Controller层用@Controller
  3. 对于上面使用的@Autowired和@Qualifier(" ")我们可以合并成一个@Resource(name= " ")
  4. @Value注入普通属性,可以通过@Value(”${ jdbc.driver}“)获取jdbc.properties文件的值,赋值给添加这个注解的变量,jdbc.properties必须在.xml配置文件中被放入容器中
@Vaule("${jdbc.driver}")
private String driver;//driver=
  1. @Scope(“”)标志Bean的作用范围,单例、多例,值为prototype和singleton
  2. @PostConstruct,使用在方法上,标注该方法是Bean的初始化方法,类似于init-method
  3. @PreDestroy,使用在方法上,标注该方法是Bean的摧毁方法,类似于destroy-method

4.2 新注解

以上原始注解,不能全部替代xml配置文件的Bean在例如连接池这种Bean中,我们不能到它的包.类去添加注解,包括组件扫描,也扫描不了

注解说明
@Configuration用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定Spring在初始化容器时哟啊扫描的包,作用和Spring的xml配置文件中的一样
@Bean使用在方法上,标注将该方法的返回值存储到Spring容器中 ,如@Bean(“dataSource”),Spring会将当前方法的返回值以指定名称(dataSource)存储到Spring容器中
@PropertySource用来加载.properties文件中的配置,作用和Spring的xml配置文件中的 一样
@Import用于导入其他配置文件,作用和Spring的xml配置文件中的一样,@Import({XXX.class,XXX.xml})可以导入多个配置文件

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/737620.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存