狂神说-Spring学习总结

狂神说-Spring学习总结

初始Spring

软件开发中的各个版本

Alpha:是内部测试版,一般不向外部发布,会有很多Bug.一般只有测试人员使用。

Beta:也是测试版,这个阶段的版本会一直加入新的功能。在Alpha版之后推出。

RC:(Release Candidate) 顾名思义, 用在软件上就是候选版本。系统平台上就是发行候选版本。RC 版不会再加入新的功能了,主要着重于修复测试中发现的缺陷。

GA : General Availability,正式发布的版本,国外通常用 GA 来标识 release 版本,GA 版本是开发团队认为该版本是稳定版(有的软件可能会标识为 Stable 版本或者 Production 版本,其意思和 GA 相同),可以在较为关键的场合使用,比如生产环境。

snapshots快照版本,代表正在开发中的版本,一般处于开发阶段,0.0.1版本还有功能没有完成,或还有bug还要修复,所以这个阶段一般代码更新比较频繁

release代表比较稳定的发布版本,次迭代的所有功能都已经完成,并且通过了测试之后,就可以发布为0.0.1-Release版本,Release版的一旦发布,就不要再改变代码了,所以如果之后在0.0.1-Release这个版本上发现了bug,需要修复,那么我们应该将0.0.1-Release版本改为0.0.2-SNAPSHOT,然后再修改bug并测试,没问题之后将0.0.2-SNAPSHOT改为0.0.2-Release发布.

简介

  • Spring:春天,给软件行业带来了春天!

  • 2002年,首次推出Spring框架的雏形,interface21框架

  • Spring框架以interface21框架为基础经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版本。

  • Rod Johnson,Spring framwork创始人,他的专业不是计算机,而是音乐家。

  • Spring理念:使现有技术更容易使用。本身是一个大杂烩,整合了现有的技术框架!

  • SSH : Struct2 + Spring + Hibernate

  • SSM : SpringMVC + Spring + Mybatis

官网:https://docs.spring.io/spring-framework/docs/current/reference/html/overview.html#overview

官方下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring

<dependencies>
        <!-- https://mvnrepository.com/artifact/springframework/spring-webmvc -->
        <dependency>
            <groupId>springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>1.2.6</version>
        </dependency>
    </dependencies>


<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.9</version>
</dependency>

优点

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

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

组成

七大模块
在这里插入图片描述

拓展

  • Spring Boot

    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速开发单个服务
    • 约定大约配置
  • Spring Cloud

    • Spring Cloud是基于SpringBoot实现的

学习SpringBoot的前提是,学习Spring和SpringMVC!

弊端:发展太久了了,违背了原来的理念!配置十分繁琐,人称"配置地狱"!

IOC 理论推导

导包

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>

常规写法

  1. UserDao

    package com.hopeful.dao;
    
    public interface IUserDao {
        public void getUser();
    }
    
  2. UserDaoImpl

    package com.hopeful.dao;
    
    public class UserDaoImpl implements IUserDao {
        public void getUser() {
            System.out.println("默认获取用户");
        }
    }
    
  3. UserService

    package com.hopeful.service;
    
    import com.hopeful.dao.IUserDao;
    import com.hopeful.dao.UserDaoImpl;
    
    public interface IUserService {
        public void getUser();
    }
    
  4. UserServiceImpl

    package com.hopeful.service;
    
    import com.hopeful.dao.IUserDao;
    import com.hopeful.dao.UserDaoImpl;
    import com.hopeful.dao.UserMySQLImpl;
    
    
    public class UserServiceImpl implements IUserService {
    //    public IUserDao userDao = new UserDaoImpl();
    
        public IUserDao userDao = new UserMySQLImpl();
        public void getUser() {
            userDao.getUser();
        }
    }
    
  5. 测试

    package com.hopeful.service;
    
    public class MyTest {
    
        public static void main(String[] args) {
            IUserService userServie = new UserServiceImpl();
            userServie.getUser();
        }
    }
    

如果突然增加一个实现IUserDao接口的实现类,则需要修改Service层的代码,十分繁琐,如果代码量特别大,则维护的成本,就十分昂贵了。具体如下:

package com.hopeful.dao;

import com.hopeful.service.IUserService;

public class UserMySQLImpl implements IUserDao {
    public void getUser() {
        System.out.println("获取SQL用户");
    }
}

UserServiceImpl修改为:

package com.hopeful.service;

import com.hopeful.dao.IUserDao;
import com.hopeful.dao.UserDaoImpl;
import com.hopeful.dao.UserMySQLImpl;

public class UserServiceImpl implements IUserService {
//    public IUserDao userDao = new UserDaoImpl();

    public IUserDao userDao = new UserMySQLImpl();
    public void getUser() {
        userDao.getUser();
    }
}

注入写法

使用Setter接口实现革命性的变化,具体如下:

UserServiceImpl修改为

package com.hopeful.service;

import com.hopeful.dao.IUserDao;
import com.hopeful.dao.UserDaoImpl;
import com.hopeful.dao.UserMySQLImpl;

import java.util.Set;


public class UserServiceImpl implements IUserService {
//    public IUserDao userDao = new UserDaoImpl();

//    public IUserDao userDao = new UserMySQLImpl();


    public IUserDao userDao;

    // 利用set方法动态实现对象的绑定
    public void setUserDao(IUserDao userDao) {
        // 此处必须写this,不然会出现空指针
        this.userDao = userDao;
    }
    public void getUser() {
        userDao.getUser();
    }
}

测试

package com.hopeful.service;


import com.hopeful.dao.UserMySQLImpl;

public class MyTest {

    public static void main(String[] args) {
        IUserService userServie = new UserServiceImpl();
        ((UserServiceImpl)userServie).setUserDao(new UserMySQLImpl());
        userServie.getUser();
    }
}

原来是程序主动创建对象,也就是需要程序猿主动创建

使用set注入后,程序不再具有主动性,而是变成了被动地接收对象,即现在创建的主动权交给用户,需要哪个创建哪个。

程序耦合性低,便于维护。

总结:这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了,系统的耦合大大降低了,可以更加专注的在业务的实现上。这是IOC的原型。

IOC的本质

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

在这里插入图片描述

Spring中IOC容器

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

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

HelloSpring案例

导包

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>

如果父工程已经导入过了,则可省略此处。

编写配置文件

<?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">


<!--使用Spring来创建对象,在Spring这些都称为Bean
类型 变量名 = new 类型();
Hello hello = new Hello();

id = 变量名
class = new的对象
property 相当于给对象中的属性设置一个值!
    -->
<bean id="hello" class="com.hopeful.pojo.Hello">
    <property name="name" value="Hello Spring"/>
</bean>
</beans>

建立实体类

@Data
public class Hello {
    private String name;
}

测试

@Test
public void TestStr() {
    //获取Spring的上下文对象!
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

    //我们的对象现在都在Spring中的管理了,我们需要使用,直接去里面取出来就可以!
    Hello hello = (Hello) context.getBean("hello");
    System.out.println(hello.toString());
}

由上述案例可见,使用对象,没有使用关键字new来创建对象。也就是spring框架对对象进行了管理,即创建,管理和装配。

思考问题

  • 对象是由谁创建的?

    Hello是由Spring创建的

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

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

这个过程就叫控制反转:

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

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

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

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

可以通过newClassPathXmlApplicationContext去浏览一下底层源码。

OK,到现在,我们彻底不中用再程序中去改动了,要实现不同的操作,只需要再xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配!

遇到的问题

applicationContext无法找到getBean方法

解答1: 添加setter和getter方法

解答2: 修改加载的包为 org.springframework.context.ApplicationContext

解答3:手动加载依赖,file -> Project Structure

在这里插入图片描述
在这里插入图片描述

选择需要的库即可

在这里插入图片描述

最后别忘记点击 application或应用,嘻嘻,我的问题就解决了!

Compilation failed: internal java compiler error

编辑版本和jdk版本不一致

可参考文档:https://blog.csdn.net/shizheng_Li/article/details/107050180

org.springframework.beans.factory.config.ConfigurableListableBeanFactory.getApplicationStartup()Lorg…

依赖版本与加载版本不同导致的,我当初用的是spring5.3.9,后来改用5.2.0,导致这样的错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3OJEjEdv-1635118396040)(Spring.assets/image-20210917070202185.png)]

调整为自己需要的版本即可!

整合之前的常规写法

  1. 在原来常规写法的基础上,添加配置文件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
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userDaoImpl" class="com.hopeful.dao.UserDaoImpl" />
        <bean id="userMySQLImpl" class="com.hopeful.dao.UserMySQLImpl" />
        <bean id="userOracleImpl" class="com.hopeful.dao.UserOracleImpl" />
        <bean id="userServiceImpl" class="com.hopeful.service.UserServiceImpl">
            <!-- ref 引用spring容器中的bean -->
            <property name="userDao" ref="userOracleImpl"/><!-- 此处只需要修改ref的值,就可以实现调用不同的实现类 -->
        </bean>
    
    </beans>
    
  2. 测试

    @Test
    public void testIOC() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserServiceImpl userServiceImpl = context.getBean("userServiceImpl", UserServiceImpl.class);
        userServiceImpl.getUser();
    }
    

Spring创建的方式

  1. 环境准备
package com.hopeful.pojo;

public class User {

    private String name;

    public User() {
        System.out.println("user通过无参构造函数创建了");
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
  1. 测试

    package com.hopeful.pojo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
        public static void main(String[] args) {
            // 无参函数被调用了
            User user = new User(); // user通过无参构造函数创建了
        }
    }
    

基于 Setter 的依赖项Setter方法

创建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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.hopeful.pojo.User"></bean>

</beans>

测试

package com.hopeful.pojo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        // spring默认通过无参构造构建
        User user = (User)context.getBean("user");  // user通过无参构造函数创建了

    }
}

Constructor构建

构造函数参数索引

<bean id="user" class="com.hopeful.pojo.User">
    <constructor-arg index="0" value="Hopeful"></constructor-arg>
</bean>

构造函数参数类型匹配,不建议

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

构造函数参数名称,推荐使用

<bean id="user" class="com.hopeful.pojo.User">
    <constructor-arg name="name" value="Hopeful3"/>
</bean>

总结:在配置文件加载的时候,容器中管理的对象就已经初始化了! 多次从容器中获取的对象都是同一对象。

Spring配置

alis别名

<alias name="user" alias="userNew"/>

bean的配置

<!--    id:唯一标识符,也就是相当于我们的对象名-->
<!--    class: bean对象的全限定类名,包名 + 类型-->
<!--    name: 也是别名,而且可以起多个别名,用空格/逗号/分号都分割-->
<!--    scopt: 作用域,作用那个范围-->
    
    <bean id="user" class="com.hopeful.pojo.User" name="user2,u2;u3 u4" scope="singleton">
        <constructor-arg name="name" value="Hopeful3"/>
    </bean>

import

<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.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
        http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    id:唯一标识符,也就是相当于我们的对象名-->
<!--    class: bean对象的全限定类名,包名 + 类型-->
<!--    name: 也是别名,而且可以起多个别名,用空格/逗号/分号都分割-->
<!--    scopt: 作用域,作用那个范围-->

    <bean id="user" class="com.hopeful.pojo.User" name="user2,u2;u3 u4" scope="singleton">
        <constructor-arg name="name" value="Hopeful3"/>
    </bean>

</beans>

依赖注入

构造器注入

前面讲过了

Set方法注入【重点】

  • 依赖注入: Set注入

    • 依赖: bean的创建需要依赖与容器
    • 注入: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">
    <!--    <bean id="student" class="com.hopeful.pojo.Student" name="user2,u2;u3 u4">-->
    <!--        <constructor-arg name="name" value="Hopeful3"/>-->
    <!--    </bean>-->
    
        <bean id="address" class="com.hopeful.pojo.Address"></bean>
    
        <bean id="student" class="com.hopeful.pojo.Student" name="user2,u2;u3 u4">
            <property name="name" value="StudentName"></property>
            <property name="address" ref="address"></property>
    
            <property name="books">
                <array>
                    <value>西游记</value>
                    <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="2334342343453453"></entry>
                    <entry key="银行卡" value="23434543545456456"/>
                </map>
            </property>
    
            <property name="games">
                <set>
                    <value>LOL</value>
                    <value>贪吃蛇</value>
                </set>
            </property>
    
    
    		<!--  null 值-->
            <property name="wife">
                <null/>
            </property>
    
            <property name="info">
                <props>
                    <prop key="姓名">张三</prop>
                    <prop key="性别"></prop>
                </props>
            </property>
        </bean>
    </beans>
    

拓展方式注入

官方解释 :

在这里插入图片描述
在这里插入图片描述

实体类

package com.hopeful.pojo;

public class User {

    private String name;
    private String pwd;

    public User() {
    }

    public User(String name, String pwd) {
        this.name = name;
        this.pwd = pwd;
    }

    public String getName() {
        return name;
    }

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

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

xml文件,c-namespace和p-namespace

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

    <bean id="user" class="com.hopeful.pojo.User" >
        <property name="name" value="Hopeful"/>
        <property name="pwd" value="123456"/>
    </bean>
    <!--   p namespace property注入 相当于上方的-->
    <bean id="user2" class="com.hopeful.pojo.User" p:name="Hopeful2" p:pwd="222222"></bean>


    <bean id="user3" class="com.hopeful.pojo.User">
        <constructor-arg name="name" value="Hopeful3"></constructor-arg>
        <constructor-arg name="pwd" value="33333333"/>
    </bean>
    <!--  c-namespace constructor注入 相当于上方的 -->
    <bean id="user4" class="com.hopeful.pojo.User" c:name="Hopeful3" c:pwd="3333333333"/>

</beans>

测试

package com.hopeful;

import com.hopeful.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class MyUserTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("userBean.xml");
//        User users = context.getBean("user1", User.class);
//        User users = context.getBean("user2", User.class);
//        User users = context.getBean("user3", User.class);
        User users = context.getBean("user4", User.class);
        System.out.println(users);
    }
}

beans作用域

在这里插入图片描述

  1. 单例模式 应用中只有一个实例

    <bean id="user" class="com.hopeful.pojo.User" scope="singleton">
        <property name="name" value="Hopeful"/>
        <property name="pwd" value="123456"/>
    </bean>
    
    public class MyUserTest {
        public static void main(String[] args) {
    
            ApplicationContext context = new ClassPathXmlApplicationContext("userBean.xml");
            User users = context.getBean("user", User.class);
            User users2 = context.getBean("user", User.class);
            System.out.println(users == users2);  // true
        }
    }
    

    特点:使用于单线程,并发时使用该模式,容易产生一些延迟

  2. 原型模式 每次获取创建不同实例

<bean id="user" class="com.hopeful.pojo.User" scope="prototype">
    <property name="name" value="Hopeful"/>
    <property name="pwd" value="123456"/>
</bean>
public class MyUserTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("userBean.xml");
        User users = context.getBean("user", User.class);
        User users2 = context.getBean("user", User.class);
        System.out.println(users == users2); // false
    }
}

特点:比较浪费资源,但多线程不会出现问题

自动装配

  • ByName 通过名称装配

    <!--    ByName: 会自动在容器上下文中查找,和自己对象Set方法后面对应的beanId-->
    <bean id="person" class="com.hopeful.pojo.Person" autowire="byName">
        <property name="name" value="Hopeful"/>
    </bean>
    
  • ByType 通过类型装配

    <!--    ByType: 会自动在容器上下文中查找,和自己对象类型相同的bean-->
    <bean id="person" class="com.hopeful.pojo.Person" autowire="byType">
        <property name="name" value="Hopeful"/>
    </bean>
    

ByName 通过名称装配,需保证所有bean的id唯一,该ID名称需要和set方法后面的名称保持一致!

ByType 通过类型装配,需保证所有bean的class唯一,该类型需要在应用中全局唯一!

@Autowired

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

    <!--    开启使用注解 -->
    <context:annotation-config/>
    <bean id="dog" class="com.hopeful.pojo.Dog"/>
    <bean id="cat" class="com.hopeful.pojo.Cat"/>
    

    <bean id="person" class="com.hopeful.pojo.Person">
        <property name="name" value="Hopeful"/>
    </bean>

</beans>

实体类

package com.hopeful.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;

    @Autowired
    private Dog dog;

    @Autowired
    private Cat cat;
}

测试

package com.hopeful.pojo;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

public class MyTest {

    @Test
    public void testAutowired() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Person person = context.getBean("person", Person.class);
        person.getCat().shut();
        person.getDog().shut();
    }
}

使用要求:

  1. 导入约束:context 约束
  2. 配置注解的支持:<context:annotation-config/>

注意:

  • 直接在属性上使用即可!也可以在set方法上使用
  • 使用Autowired,我们可以不用编写Set放高发了,前提是你这个自动装配的属性在IOC容器中,且类型符合ByType或byName

ByName

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


    <context:annotation-config/>

    <!--使用Spring来创建对象,在Spring这些都称为Bean
    类型 变量名 = new 类型();
    Hello hello = new Hello();

    id = 变量名
    class = new的对象
    property 相当于给对象中的属性设置一个值!-->

    <bean id="dog" class="com.hopeful.pojo.Dog"/>
    <bean id="dog2" class="com.hopeful.pojo.Dog"/>

    <bean id="person" class="com.hopeful.pojo.Person">
    </bean>


</beans>
package com.hopeful.pojo;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;


@Data
public class Person {

    private String name;

	// 通过ByName装配成功
    @Autowired
    private Animal dog;

}

ByType

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


    <context:annotation-config/>

    <!--使用Spring来创建对象,在Spring这些都称为Bean
    类型 变量名 = new 类型();
    Hello hello = new Hello();

    id = 变量名
    class = new的对象
    property 相当于给对象中的属性设置一个值!-->

    <bean id="dog1" class="com.hopeful.pojo.Dog"/>

    <bean id="person" class="com.hopeful.pojo.Person">
    </bean>
</beans>
package com.hopeful.pojo;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;


@Data
public class Person {

    private String name;

	// 通过ByType装配成功
    @Autowired
    private Animal dog;

}

科普:

// 添加required = false 属性,代表该属性可以为null,否则不能为null(默认为true)
    @Autowired(required = false)

// 注解@Autowired源码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

如果@Autowired自动装配的环境比较复杂,自动装配无法确认装配具体的bean(存在类型相同的bean),则@Autowired注解就无法单独完成装配,我们可以使用@Qualifier(value=“beanName”)去装配,指定唯一的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"
       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
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--    开启使用注解 -->
    <context:annotation-config/>
    <bean id="dog1" class="com.hopeful.pojo.Dog"/>
    <bean id="dog2" class="com.hopeful.pojo.Dog"/>
    <bean id="cat1" class="com.hopeful.pojo.Cat"/>
    <bean id="cat2" class="com.hopeful.pojo.Cat"/>


    <bean id="person" class="com.hopeful.pojo.Person">
        <property name="name" value="Hopeful"/>
    </bean>

</beans>

实体类

package com.hopeful.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;

    // 添加required = false 属性,代表该属性可以为null,否则不能为null(默认为true)
    @Autowired(required = false)
    @Qualifier(value = "dog1")
    private Dog dog;

    @Autowired
    @Qualifier(value = "cat1")
    private Cat cat;
}

测试,见上方。

@Resource

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

    <!--    开启使用注解 -->
    <context:annotation-config/>
    <bean id="dog1" class="com.hopeful.pojo.Dog"/>
    <bean id="dog2" class="com.hopeful.pojo.Dog"/>
    <bean id="cat1" class="com.hopeful.pojo.Cat"/>
    <bean id="cat2" class="com.hopeful.pojo.Cat"/>


    <bean id="person" class="com.hopeful.pojo.Person">
        <property name="name" value="Hopeful"/>
    </bean>

</beans>

实体类

package com.hopeful.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Value;

import javax.annotation.Resource;
import javax.annotation.Resources;


/**
 * Person
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/9/24 7:36]
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;

    @Resource(name = "dog1")
    public Dog dog;


    @Resource(name = "cat2")
    private Cat cat;
}

测试

package com.hopeful.pojo;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

/**
 * MyTest
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/9/24 7:41]
 */
public class MyTest {

    @Test
    public void testAutowired() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Person person = context.getBean("person", Person.class);
        person.getCat().shut();
        person.getDog().shut();
    }
}

@Resource 集合了ByName和ByType两方的特性,默认通过ByName查找,如果找不到,再通过ByType查找,如果都找不到,则报错,但可以通过属性name指定特定的bean。

ByName和ByType两方测试可参考@Autowired测试

@Autowired和@Resource异同

总结:

相同:@Autowired和@Resource都是自动装配使用的,都可以在属性上使用

不同:

  • @Autowired 通过ByType或ByName 装配bean
  • @Resource 先通过ByName装配,找不到,再通过ByType装配,否则报错,但可以通过name属性,指定特定名称的bean
//    @Autowired
//    @Qualifier(value = "dog1")
    @Resource(name = "dog1")   // 以上两个注解,相当于下面一个注解,但java注解@Resource没有提示
    private Animal dog;

Spring 注解开发

spring4之后,使用注解开发,必须导入aop的包。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iHuYDiev-1635118396047)(Spring.assets/image-20210928070605050.png)]

  1. 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"
           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
            http://www.springframework.org/schema/context/spring-context.xsd">
    
    
        <context:annotation-config/>
    
        <!--    指定扫描的路径,将其中的类注册到spring容器中 -->
        <context:component-scan base-package="com.hopeful"/>
        
        <!--    <bean id="user" class="com.hopeful.pojo.User">-->
    <!--        <property name="name" value="HOPEFUL_xml_INNER"/>-->
    <!--    </bean>-->
    
    </beans>
    
  2. 属性的注入

    package com.hopeful.pojo;
    
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Repository;
    
    /**
     * User
     *
     * @author : yl
     * @version : [v1.0]
     * @createTime : [2021/9/27 20:57]
     */
    
    @Repository
    @Data
    public class User {
    
        // 相当于 xml文件中 <property name="name" value="HOPEFUL"/>
    //    @Value("HOPEFUL")
        private String name;
    
    
        @Value("HOPEFUL22")
        public void setName(String name) {
            this.name = name;
        }
    }
    

    @value属性的优先级

    xml配置文件位置优先级 > set方法 > 字段属性

  3. 衍生的注解

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

    • dao 【@Repository】
    • service 【@Service】
    • controller 【@controller】

    这四个注解功能都是一样的,都是代表将该类注解到spring容器中。

  4. 自动装配

    • @Autowired
    • @Resource
  5. 作用域

    @Scope(“singleton | prototype”)

    package com.hopeful.pojo;
    
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Repository;
    
    
    @Repository
    @Data
    @Scope("singleton")
    public class User {
    
        // 相当于 xml文件中 <property name="name" value="HOPEFUL"/>
        @Value("HOPEFUL")
        private String name;
    
    }
    

    [TOC]

  6. 最佳实践

    • xml与注解

      • xml更加万能,适用于任何场景
      • 注解不是自己的类使用不了(无法引用其他类型的bean),维护相对复杂。
    • xml与直接的最佳实践

      • xml只用来管理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"
             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
              http://www.springframework.org/schema/context/spring-context.xsd">
      
      
          <context:annotation-config/>
          <!--    指定扫描的路径,将其中的类注册到spring容器中 -->
          <context:component-scan base-package="com.hopeful"/>
      </beans>
      

使用javaConfig实现配置

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

javaConfig是Spring的一个子项目,在Spring4之后,他成为了一个核心功能!

实体类

package com.hopeful.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

public class User {

    @Value("Hopeful_appConfig")
    private String name;

    public String getName() {
        return name;
    }

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

}

配置类

package com.hopeful.config;

import com.hopeful.pojo.User;
import org.springframework.context.annotation.*;


// 本质还是一个组件,所以也会交给spring容器托管
// @Configuration 注解,表示该注解是一个配置类,相当于spring中的applicationContext.xml

//导入配置文件
//@ImportResource(locations={"classpath:applicationContext.xml"})
//spring4.2之前导入配置类
//@Import({JavaConfigA.class,JavaConfigB.class})
//spring4.2之后导入普通java bean
//@Import(DemoService.class) // 在spring 4.2之前是不支持的
    
@Configuration
@ComponentScan("com.hopeful.pojo")
@Import(AppConfig2.class)
@ImportResource(locations={"classpath:applicationContext.xml"})
public class AppConfig {

    // 此处无法跳转,只代表idea不支持
    // 注册一个bean,就相当于我们之前写的一个bean标签
    // 这个方法的名称,就相当于bean标签的id属性
    // 这个方法的返回值,就相当于bean标签的class属性
    //
    @Bean
    public User user() {
        return new User();
    }
}

测试

package com.hopeful;

import com.hopeful.config.AppConfig;
import com.hopeful.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = context.getBean("user", User.class);
        System.out.println(user.getName());
    }
}

之前使用xml配置文件,通过ClassPathXmlApplicationContext类来获取IOC容器

现在javaConfig配置,通过AnnotationConfigApplicationContext类来获取IOC容器

代理模式

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

代理分类:

  • 静态代理
  • 动态代理

租房为例

房东租房:
在这里插入图片描述

中介出租房子

在这里插入图片描述

静态代理

角色分析:

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

接口

package com.hopeful.demo1;

public interface Rent {
    public void rent();
}

真实角色

package com.hopeful.demo1;

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

代理角色

package com.hopeful.demo1;

// 中介
public class Proxy implements Rent {
    private Landlord landlord;

    public Proxy(Landlord landlord) {
        this.landlord = landlord;
    }

    public Proxy() {
    }


    public void rent() {
        lookHouse();
        landlord.rent();
        signAContract();
    }

    // 看房子
    public void lookHouse() {
        System.out.println("中介带人看房~");
    }

    // 签合同
    public void signAContract(){
        System.out.println("中介和我们签合同");
    }
}

测试

package com.hopeful.demo1;

public class Client {
    public static void main(String[] args) {

        // 直接找房东出租房子
//        Landlord landlord = new Landlord();
//        landlord.rent();


        // 通过中介租房
        Landlord landlord = new Landlord();  // 房东租赁房子
        // 代理:中介帮房东租房子,但是代理一般会有一些附属操作
        Proxy proxy = new Proxy(landlord);
        
        // 直接找中介租房,不用找房东即可
        proxy.rent();
    }
}

代理模式的好处:

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

缺点:

  • 一个真实的角色就会产生一个代理角色 ;代码会翻倍——开发效率就会变低!

代理加深理解

添加日志模块

接口

package com.hopeful.demo2;

public interface IUserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

真实角色

package com.hopeful.demo2;

/**
 * UserDao
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/9/28 22:08]
 */
public class UserService implements IUserService {
    public void add() {
        System.out.println("新增了一个用户");
    }

    public void delete() {
        System.out.println("删除 了一个用户");
    }

    public void update() {
        System.out.println("更新了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }

    // 在公司中改动业务代码,是大忌
}

代理对象

package com.hopeful.demo2;

/**
 * Proxy
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/9/28 22:16]
 */
public class Proxy implements IUserService {

    private IUserService userService;

    public void setUserService(IUserService userService) {
        this.userService = userService;
    }

    public void add() {
        log("add()");
        userService.add();
    }

    public void delete() {
        log("delete()");
        userService.delete();
    }

    public void update() {
        log("update()");
        userService.update();
    }

    public void query() {
        log("query()");
        userService.query();
    }

    public void log(String method) {
        System.out.println("【debug】 执行了" + method +"方法");
    }
}

用户

package com.hopeful.demo2;

public class Client {

    public static void main(String[] args) {
//        UserService userService = new UserService();
//        userService.add();

        Proxy proxy = new Proxy();
        proxy.setUserService(new UserService());
        proxy.add();
    }
}

动态代理

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务

  • 公共也就交给代理角色!实现业务的分工

  • 公共业务发生扩展的时候,方便集中管理!

  • 动态代理和静态代理角色一样

  • 动态代理的代理类是动态生成的,不是我们直接写好的

  • 动态代理分为两类:基于接口的动态代理,基于类的动态代理

    • 基于接口-jdk动态代理【我们在这里使用】
    • 基于类:cglib
    • java字节码实现:javasist
  • 需要了解两个类:Proxy代理,invocationHandler 调用处理程序

IUserService接口

package com.hopeful.demo2;

public interfajavace IUserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

UserService实现类

package com.hopeful.demo2;

/**
 * UserDao
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/9/28 22:08]
 */
public class UserService implements IUserService {
    public void add() {
        System.out.println("新增了一个用户");
    }

    public void delete() {
        System.out.println("删除 了一个用户");
    }

    public void update() {
        System.out.println("更新了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }

    // 在公司中改动业务代码,是大忌
}

代理处理程序

package com.hopeful.demo4;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class ProxyInvocationHandler implements InvocationHandler {

    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 生成被代理的对象
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    // 处理代理实例,并返回结果
    // 代理对象调接口中的方法---代理对象的真身是$proxy0 调用了对应的方法---此方法内部调用其父类的成员h调用h的invoke方法---就是调用传入了InvocationHandler的invoke方法,至于返回值,那就看我们的InvocationHandler的实现类怎么写了。
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object object =  method.invoke(target,args);
        return object;
    }

    public void log(String msg) {
        System.out.println("执行了"+ msg +"方法");
    }
}

测试

package com.hopeful.demo4;

import com.hopeful.demo2.IUserService;
import com.hopeful.demo2.UserService;

/**
 * Client
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/10/12 7:19]
 */
public class Client {

    public static void main(String[] args) {

        // 真实角色
        UserService userService = new UserService();


        // 代理角色 没有
        //代理调用处理程序
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService);

        // 获取代理类
        // 代理对象调接口中的方法---代理对象的真身是$proxy0 调用了对应的方法---此方法内部调用其父类的成员h调用h的invoke方法---就是调用传入了InvocationHandler的invoke方法,至于返回值,那就看我们的InvocationHandler的实现类怎么写了。
        IUserService proxy = (IUserService) pih.getProxy();
        proxy.delete();
    }

}

代理模式的好处:

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

聊聊AOP

在这里插入图片描述

AOP

AOP的Spring原生实现-使用Spring API 接口

1.引入依赖:

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>

2.编写接口与实现类

package com.hopefu.service;

public interface IUserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}
package com.hopefu.service;

public class UserServiceImpl implements IUserService {
    @Override
    public void add() {
        System.out.println("执行了add方法");
    }

    @Override
    public void delete() {
        System.out.println("执行了delete方法");
    }

    @Override
    public void update() {
        System.out.println("执行了update方法");
    }

    @Override
    public void select() {
        System.out.println("执行了select方法");
    }
}

3.编写日志

package com.hopefu.log;

import org.springframework.aop.AfterAdvice;
import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回值是"+o);
    }
}
package com.hopefu.log;

import org.springframework.aop.AfterAdvice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import javax.sound.midi.Soundbank;
import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法前打印日志");
    }
}

4.编写配置文件

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


    <bean id="userService" class="com.hopefu.service.UserServiceImpl"></bean>
    <bean id="afterLog" class="com.hopefu.log.AfterLog"></bean>
    <bean id="beforeLog" class="com.hopefu.log.BeforeLog"></bean>

    <aop:config>
<!--        切入点:expression:表达式,execution(* * * * *)-->
        <aop:pointcut id="pointcut" expression="execution(* com.hopefu.service.UserServiceImpl.*(..))"/>

<!--        环绕通知增强-->
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
    </aop:config>

</beans>

测试

package com.hopeful.service;

import com.hopefu.service.IUserService;
import com.hopefu.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * MyTest
 *
 * @author : yl
 * @version : [v1.0]
 * @createTime : [2021/10/13 21:06]
 */
public class MyTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        IUserService userService = context.getBean("userService", IUserService.class);
        userService.add();
    }
}

自定义AOP

package com.hopeful.diy;

public class PoinCutDiy {
    public void before() {
        System.out.println("before");
    }

    public void after() {
        System.out.println("after");
    }
}

编写接口IUserService与实现类UserServiceImpl参考使用SpringAPI接口的案例

配置文件

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

    <!-- 方式二 -->
    <bean id="userService" class="com.hopeful.service.UserServiceImpl"/>
    <bean id="pointCutDiy" class="com.hopeful.diy.PoinCutDiy"/>
    <aop:config>
        <aop:aspect ref="pointCutDiy">
            <aop:pointcut id="point" expression="execution(* com.hopeful.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

</beans>

测试:参考使用SpringAPI接口的案例
Spring-AOP中Pointcut中Expression表达式的学习可参考:Spring-AOP中Pointcut中Expression表达式

使用注解

自定义切面

package com.hopeful.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect  // 标记切面
public class AnnotationPointDiy {
//    前置通知
    @Before("execution(* com.hopeful.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("执行方法前==========");
    }


//    后置通知
    @After("execution(* com.hopeful.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println("执行方法后===========");
    }


//    环绕通知
    @Around("execution(* com.hopeful.service.UserServiceImpl.*(..))")
    //    pj 连接点 可以获取执行方法的一些方法
    public void around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("环绕通知前=========");

        // 通过连接点调用执行的方法
        Object proceed = pj.proceed();
        System.out.println("环绕通知后=========");
    }
}

编写接口IUserService与实现类UserServiceImpl参考使用SpringAPI接口的案例

配置文件

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

    <!--注册bean-->
    <bean id="annotationPointDiy" class="com.hopeful.diy.AnnotationPointDiy"/>
    <bean id="userService" class="com.hopeful.service.UserServiceImpl"/>
	<!-- 开启注解支持-->
    <aop:aspectj-autoproxy/>

</beans>

测试:参考使用SpringAPI接口的案例

AOP在Spring中的作用

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

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

方式一:使用Spring 的API接口

方法 二:自定义AOP

方法三:使用注解

整合Mybatis和Spring

回顾Mybatis

  1. 添加依赖
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.10</version>
    </dependency>


    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.10</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.7</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
        <scope>provided</scope>
    </dependency>

</dependencies>

在这里插入图片描述

总结:我们平常最大的scope疑问在provided 和 runtime之间。记住一个原则就行,如果容器有的jar,在项目pom.xml中就使用provided; 如果需要动态加载的jar就使用runtime 。默认scope是compile

  1. 创建实体类

    package com.hopeful.pojo;
    
    import lombok.Data;
    
    @Data
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  2. 编写核心配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <package name="com.hopeful.pojo"/>
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="com/hopeful/mapper/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  3. 编写接口

    package com.hopeful.dao;
    
    import com.hopeful.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        List<User> selectUser();
    }
    
  4. 编写mapper.xml文件

    <?xml version="1.0" encoding="UTF8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.hopeful.dao.UserMapper">
    
        <select id="selectUser" resultType="user">
            select * from user;
        </select>
    </mapper>
    
  5. 测试

    package com.hopeful.test;
    
    import com.hopeful.dao.UserMapper;
    import com.hopeful.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.ognl.security.UserMethod;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    public class MyTest {
    
        @Test
        public void selectUsers() throws IOException {
            String resource = "mybatisConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> usersList = mapper.selectUser();
            for (User user : usersList) {
                System.out.println(user);
            }
        }
    }
    

整合一

  1. 配置数据源

  2. 配置SqlSessionFactory

  3. 配置SqlSessionTemplate

    <?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">
    
    <!--    dataSource:使用spring中JDBC数据源 -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>
    
        <!-- SqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <!-- 绑定mybatis配置文件 -->
            <property name="configLocation" value="classpath:mybatisConfig.xml"/>
            <property name="mapperLocations" value="classpath:com/hopeful/mapper/*.xml"/>
        </bean>
    
    <!--    sqlSessionTemplate:就是我们使用的sqlSession -->
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!--        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
            <constructor-arg index="0" ref="sqlSessionFactory"/>
        </bean>
    
    <!-- 将接口实现类注册到spring容器中 -->
        <bean id="userMapper" class="com.hopeful.dao.UserMapperImpl">
            <property name="sqlSession" ref="sqlSession"/>
        </bean>
    </beans>
    
  4. 编写接口Mapper实现类

    package com.hopeful.dao;
    
    import com.hopeful.pojo.User;
    import org.mybatis.spring.SqlSessionTemplate;
    
    import java.util.List;
    
    public class UserMapperImpl implements UserMapper {
    
        private SqlSessionTemplate sqlSession;
    
        public void setSqlSession(SqlSessionTemplate sqlSession) {
            this.sqlSession = sqlSession;
        }
    
        public List<User> selectUser() {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            return mapper.selectUser();
        }
    }
    
  5. 测试

    package com.hopeful.test;
    
    import com.hopeful.dao.UserMapper;
    import com.hopeful.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.ognl.security.UserMethod;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import javax.jws.soap.SOAPBinding;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    public class MyTest {
    
        @Test
        public void selectUsers() throws IOException {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
    
            UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
            List<User> users = userMapper.selectUser();
    
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
    

方式二:使用SqlSessionDaoSupport

编写 实现类

package com.hopeful.dao;

import com.hopeful.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

// SqlSessionDaoSupport 提供SqlSessionTemplate
// 继承sqlSessionDaoSupport可以通过getSqlSession获取sqlSession
public class UserMapperImpl3 extends SqlSessionDaoSupport implements UserMapper {

    public List<User> selectUser() {
        // 调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

测试

package com.hopeful.test;

import com.hopeful.dao.UserMapper;
import com.hopeful.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.ognl.security.UserMethod;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.jws.soap.SOAPBinding;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {

    @Test
    public void selectUsers() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");

        UserMapper userMapper = context.getBean("userMapper3", UserMapper.class);
        List<User> users = userMapper.selectUser();

        for (User user : users) {
            System.out.println(user);
        }
    }
}

方式二:

通过MapperFactoryBean 将接口加入到 Spring 中

<bean id="userMapper2" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.hopeful.dao.UserMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

实现类

package com.hopeful.dao;

import com.hopeful.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl2 implements UserMapper {

    private UserMapper userMapper;

    public List<User> selectUser() {
        return userMapper.selectUser();
    }
}

测试

@Test
    public void selectUsers() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
        List<User> users = userMapper.selectUser();

        for (User user : users) {
            System.out.println(user);
        }
    }

遇到的问题

2字节的UTF-8序列的字节2无效

使用标签时,也出现这种情况。

这个问题是因为在xml文件中的中文注释的问题,有两种解决方案:

一、将xml文件的中文注释全部删除,解决

二、将xml文件顶部的encoding=UTF-8改为encoding=UTF8可以解决问题

特殊技能

想随意调节B站倍速播放 ,谷歌浏览器按f12,点选console
输入 document.querySelector(“video”).playbackRate = 3;

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


<!--使用Spring来创建对象,在Spring这些都称为Bean
类型 变量名 = new 类型();
Hello hello = new Hello();

id = 变量名
class = new的对象
property 相当于给对象中的属性设置一个值!
    -->
<bean id="hello" class="com.hopeful.pojo.Hello">
    <property name="name" value="Hello Spring"/>
</bean>
</beans>

自动装配配置

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

    <!--    开启使用注解 -->
    <context:annotation-config/>
    <bean id="dog" class="com.hopeful.pojo.Dog"/>
    <bean id="cat" class="com.hopeful.pojo.Cat"/>
    

    <bean id="person" class="com.hopeful.pojo.Person">
        <property name="name" value="Hopeful"/>
    </bean>

</beans>

Spring注解

@Autowired

注意:

  • 直接在属性上使用即可!也可以在set方法上使用
  • 使用Autowired,我们可以不用编写Set放高发了,前提是你这个自动装配的属性在IOC容器中,且类型符合ByName或ByType

@Resource

该注解集成了ByName和ByType属性,先通过ByName查找,然后通过ByType查找,找不到报错,但可以通过name属性指定特定名称的bean。

相同:@Autowired和@Resource都是自动装配使用的,都可以在属性上使用

不同:

  • @Autowired 通过ByType 或ByName 装配bean
  • @Resource 先通过ByName装配,找不到,再通过ByType装配,否则报错,但可以通过name属性,指定特定名称的bean

@Nullable

从 Spring Framework 5.0 开始,您还可以使用@Nullable注解

@Nullable:表示特定参数,返回值或字段可以是null的 注解。

@Component

使用该注解,说明该类被Spring容器管理了。

@ComponentScan

@ComponentScan(“packageName”) 告诉Spring容器哪个包下带有注解的类被扫描,并自动装入bean容器!
注:@Configuration注解申明当前类是一个配置类,相当于xml配置文件。@ComponentScan和@Configuration一起使用的原因就是基于Spring2.0中的注解配合xml配置文件的实现一样,即在xml配置文件配置ComponentScan包扫描属性。

如果类中用了@Controller,@Repository,@Service,@Component四大注解标识之一了,那么如果不加上@ComponentScan,Spring就不会自动扫描类上的四大注解中的任何一个,那么四大注解下的类就不会被Spring扫描到,更不会装入Spring容器中,因此你配置的四大注解就失去了作用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值