2 Spring

一个Spring程序

导入Spring依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

编写实体类

package com.qin.pojo;

public class Hello {
    private String str;

    public Hello() {
    }

    public Hello(String str) {
        this.str = str;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

编写spring xml配置文件

官网模板:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="hello" class="com.qin.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>

</beans>

测试

@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Hello hello = (Hello) context.getBean("hello");
    System.out.println(hello);
}

控制反转

模拟dao层

在这里插入图片描述

模拟service层

在这里插入图片描述

配置文件

<?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">
    
    <bean id="userDaoImpl" class="com.qin.dao.UserDaoImpl"/>
    <bean id="userDaoSqlImpl" class="com.qin.dao.UserDaoSqlImpl"/>
    <bean id="userServiceImpl" class="com.qin.service.UserServiceImpl">
        <property name="userDao" ref="userDaoSqlImpl"/>
    </bean>
</beans>

测试

@Test
public void test2(){
    ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
    UserService userServiceImpl = (UserService) classPathXmlApplicationContext.getBean("userServiceImpl");
    userServiceImpl.getUser();
}

这样写就不用修改源码,只需要修改xml配置文件即可满足不用要求

IOC创建对象方式

默认使用无参构造,如果没有无参构造则必须声明有参构造方式

下标创建

<!--    下标赋值-->
<bean id="user" class="com.qin.pojo.User">
    <constructor-arg index="0" value="lol"/>
</bean>

类型创建

<!--    通过类型创建,不建议使用-->
<bean id="user" class="com.qin.pojo.User">
    <constructor-arg type="java.lang.String" value="lol"/>
</bean>

参数名创建

<!--    直接通过参数名创建-->
<bean id="user" class="com.qin.pojo.User">
    <constructor-arg name="name" value="lol"/>
</bean>

在配置文件加载的时候,spring容器中的对象就已经初始化了

Spring配置

别名

<!--如果添加了别名,也可以使用别名获得bean-->
<alias name="user" alias="userAlias"/>

Bean的配置

<!--
	id: bean的唯一标识符,也就是对象名
	class: bean对象所对应的全限定名: 包名+类型
	name:别名,可以同时取多个别名
-->
<bean id="userT" class="com.qin.pojo.User" name="n1 n2,n3;n4">
</bean>

import

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

假设,现在项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,可以利用import将所有人的beans.xml合并为一个总的.

使用的时候直接使用总的配置就可以了

依赖注入

构造器注入

<!--    直接通过参数名创建-->
<bean id="user" class="com.qin.pojo.User">
    <constructor-arg name="name" value="lol"/>
</bean>

set注入

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

实体类

package com.qin.pojo;

import java.util.*;

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

    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

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

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

注入

<?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">
<!--    直接通过参数名创建-->
    <bean id="user" class="com.qin.pojo.User">
<!--        普通属性注入-->
        <property name="name" value="lol"/>
<!--        bean注入,注入的是一个对象-->
        <property name="address" ref="address"/>
<!--        数组注入-->
        <property name="books">
            <array>
                <value>传奇</value>
                <value>呐喊</value>
                <value>钢铁是怎样炼成的</value>
            </array>
        </property>
<!--        List注入-->
        <property name="hobbys">
            <list>
                <value>打游戏</value>
                <value>打篮球</value>
                <value>看电影</value>
            </list>
        </property>
<!--        Map注入-->
        <property name="card">
            <map>
                <entry key="学号" value="18115648"/>
                <entry key="身份证" value="0000000xx000"/>
            </map>
        </property>
<!--        Set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>DOTA</value>
            </set>
        </property>
<!--        null注入-->
        <property name="wife">
            <null/>
        </property>
<!--        properties-->
        <property name="info">
            <props>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
    <bean class="com.qin.pojo.Address" id="address">
        <property name="address" value="河南"/>
    </bean>
</beans>

P命名空间注入

实体类

package com.qin.pojo;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

beans

需要导入:xmlns:p=“http://www.springframework.org/schema/p”

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    p命名空间注入,可以直接注入属性的值-->
    <bean id="student" class="com.qin.pojo.Student" p:name="lol" p:age="18"/>
</beans>

测试

@Test
public void test02(){
    ApplicationContext context = new ClassPathXmlApplicationContext("StudentBeans.xml");
    Student student = context.getBean("student", Student.class);
    System.out.println(student);
}

本质是属性注入

C命名空间注入

需要导入:xmlns:c=“http://www.springframework.org/schema/c”

实体类

package com.qin.pojo;

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

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student() {
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    p命名空间注入,可以直接注入属性的值-->
    <bean id="student" class="com.qin.pojo.Student" p:name="lol" p:age="18"/>
    <bean id="student2" class="com.qin.pojo.Student" c:name="aaa" c:age="19"/>
</beans>

测试

@Test
public void test02(){
    ApplicationContext context = new ClassPathXmlApplicationContext("StudentBeans.xml");
    Student student = context.getBean("student", Student.class);
    Student student2 = context.getBean("student2", Student.class);
    System.out.println(student);
    System.out.println(student2);
}

作用域

ScopeDescription
singleton(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototypeScopes a single bean definition to any number of object instances.
requestScopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
sessionScopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
applicationScopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocketScopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

singleton单例模式(Spring默认机制)

<bean id="student2" class="com.qin.pojo.Student" c:name="aaa" c:age="19" scope="singleton"/>

在这里插入图片描述

prototype原型模式

<bean id="student2" class="com.qin.pojo.Student" c:name="aaa" c:age="19" scope="prototype"/>
@Test
public void test02(){
    ApplicationContext context = new ClassPathXmlApplicationContext("StudentBeans.xml");
    Student student = context.getBean("student2", Student.class);
    Student student2 = context.getBean("student2", Student.class);
    System.out.println(student);
    System.out.println(student2);
    System.out.println(student==student2);//false
}

在这里插入图片描述

自动装配

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

spring有三种装配的方式

  1. 在xml中显示配置
  2. 在java中显示配置
  3. 隐式的自动装配bean

配置

实体类

public class Cat {
    public void say(){
        System.out.println("miao");
    }
}
public class Dog {
    public void say(){
        System.out.println("wang");
    }
}
package com.qin.pojo;

public class People {
    private Cat cat;
    private Dog dog;
    private String name;



    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

配置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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="cat" class="com.qin.pojo.Cat"/>
    <bean id="dog" class="com.qin.pojo.Dog"/>
    <bean id="people" class="com.qin.pojo.People">
        <property name="name" value="jack"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

</beans>

byName

    <bean id="cat" class="com.qin.pojo.Cat"/>
    <bean id="dog" class="com.qin.pojo.Dog"/>
<!--
    自动装配:
    autowire="byName" 会自动在容器上下文中找和自己对象set方法后面相对应的beanid
-->
    <bean id="people" class="com.qin.pojo.People" autowire="byName">
        <property name="name" value="jack"/>
    </bean>

byType

<bean id="cat" class="com.qin.pojo.Cat"/>
    <bean id="dog" class="com.qin.pojo.Dog"/>
<!--
    自动装配:
    byType 会自动在容器上下文中找和自己对象属性类型相对应的bean
-->
    <bean id="people2" class="com.qin.pojo.People" autowire="byType" p:name="aaa"/>

小结:

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

使用注解实现自动装配

  1. 导入约束:

    <beans 
    	xmlns:context="http://www.springframework.org/schema/context"
    
    	xsi:schemaLocation="http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    </beans>
    
  2. 配置注解的支持:

    <context:annotation-config/>
    
  3. 完整配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
</beans>

测试

@Autowired直接注解在属性上或set方法上

如果注解在属性上,可以没有set方法

package com.qin.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class People {
    @Autowired
    private Cat cat;
    
    private Dog dog;
    private String name;

    @Autowired
    public Dog getDog() {
        return dog;
    }


    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }
    

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

配置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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
<!--    开启注解的支持-->
    <context:annotation-config/>

    <bean id="people" class="com.qin.pojo.People" p:name="java"/>
    <bean id="cat" class="com.qin.pojo.Cat"/>
    <bean id="dog" class="com.qin.pojo.Dog"/>
</beans>

@Autowired是通过byType来实现自动装配的,如果有多个同类型的bean,可以通过@Qualifier(value = “beanid”)来配合使用,指定一个唯一的bean注入

@Resource注解

package com.qin.pojo;

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

import javax.annotation.Resource;
import java.lang.annotation.Retention;

public class People {
    @Resource
    private Cat cat;
    @Resource
    private Dog dog;
    private String name;
    public Dog getDog() {
        return dog;
    }
    public Cat getCat() {
        return cat;
    }
    public void setCat(Cat cat) {
        this.cat = cat;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    public String getName() {
        return name;
    
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

小结

@Resource和@Autowired的区别

  • 都可以用来自动装配的,都可以放在属性字段上
  • @Autowired通过byType的方式实现
  • @Resource默认通过byName的方式实现,如果找不到则通过byType

使用注解开发

在Spring4之后,要使用注解开发需要导入aop的包

在这里插入图片描述

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

属性注解

package com.qin.pojo;

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

//直接创建一个bean id为首字母小写的形式
//相当于<bean id="user" class="com.qin.pojo.User"/>
@Component
public class User {
    //相当于<property name="name" value="jack"/>
    @Value("jack")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

衍生注解

@Component有几个衍生注解,会按照mvc三层架构分层

  • dao(@Repository)

  • service(@Service)

  • controller(@Controller)

    这四个注解功能都是一样的,都是代表将某个类注册到Spring中

使用java的方式配置Spring

完全不使用Spring的xml配置.

JavaConfig是Spring的一个子项目,在Spring4之后变成了一个核心功能

package com.qin.pojo;

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

@Component
public class User {

    @Value("lol")
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
package com.qin.config;

import com.qin.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//这个也会被Spring容器托管,注册到容器中,因为它本质也是@Component
//@Configuration代表这是一个配置类,类似beans.xml
@Configuration
public class JavaConfig {
    //注册一个bean,相当于bean标签
    //这个方法的名字,相当于beanid
    //这个方法的返回值,相当于bean中的class属性
    @Bean
    public User getUser(){
        return new User();
    }
}
import com.qin.config.JavaConfig;
import com.qin.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Mytest {
    @Test
    public void test01(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
        User getUser = applicationContext.getBean("getUser", User.class);
        System.out.println(getUser.getName());
    }
}

静态代理

在这里插入图片描述

角色分析

  • 抽象角色:一般会使用接口或者抽象类
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,会做一些附属操作
  • 客户:访问代理对象
  1. 接口

    //租房
    public interface Rent {
        public void rent();
    }
    
  2. 真实对象

    //房东
    public class Host implements Rent {
        public void rent() {
            System.out.println("房东出租房");
        }
    }
    
  3. 代理对象

    //中介
    public class Agency implements Rent {
        private Host host;
        public Agency(){}
    
        public Agency(Host host) {
            this.host = host;
        }
    
        public void rent() {
            host.rent();
            seeHost();
            contract();
        }
        //中介的其他操作
        public void seeHost(){
            System.out.println("看房");
        }
        public void contract(){
            System.out.println("签合同");
        }
    }
    
  4. 客户端

    //客户
    public class Client {
        public static void main(String[] args) {
            Host host = new Host();
            Agency agency = new Agency(host);
            agency.rent();
        }
    }
    

代理模式的好处:

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

缺点:

  • 一个真实角色就会产生一个代理角色,增加代码量,开发效率低

模拟业务

业务接口

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

业务实现类

public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("增加用户");
    }

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

    public void update() {
        System.out.println("修改用户");
    }

    public void query() {
        System.out.println("查找用户");
    }
}

客户端类

public class Client {
    public static void main(String[] args) {
        UserService service = new UserServiceImpl();
        service.add();
    }
}

代理类

如果此时想增加一些功能,遵循开闭原则,就需要一个代理类在不改变原有代码的基础上增加功能

package com.qin.proxy2;

public class UserServiceProxy implements UserService {
    private UserServiceImpl userService;

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

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

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

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

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

    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}
public class Client {
    public static void main(String[] args) {
        UserServiceImpl service = new UserServiceImpl();
        UserServiceProxy userServiceProxy = new UserServiceProxy();
        userServiceProxy.setUserService(service);
        userServiceProxy.add();
    }
}

在这里插入图片描述

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口—>JDK动态代理
    • 基于类—>cglib
    • Java字节码实现—>javasist

InvocationHandler

在这里插入图片描述

InvocationHandler来执行代理类的方法

方法

Object invoke(Object proxy, Method method, Object[] args)

参数

  • proxy:调用该方法的代理实例
  • method:所述方法对应于调用代理实例上的接口方法实例
  • args:包含的方法调用传递代理实例的参数值的对象的阵列

结果

·
从代理实力上的方法调用返回的值

Proxy

在这里插入图片描述

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);
    }
    //处理代理类的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(target, args);
        return invoke;
    }
}
import com.qin.proxy2.UserService;
import com.qin.proxy2.UserServiceImpl;

public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler();
        invocationHandler.setTarget(userService);
        UserService proxy = (UserService) invocationHandler.getProxy();
        proxy.add();
    }
}

动态代理的好处

  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类

AOP

在这里插入图片描述

方式一:Spring API接口

导入依赖:

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

切入的方法

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

//切面中的具体方法
//执行方法前
public class Before implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(method.getName()+"方法执行前");
    }
}

注册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" 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="before" class="com.qin.log.Before"/>
    <bean id="userService" class="com.qin.service.UserServiceImpl"/>

<!--    方式一:使用原生Spring API接口-->
<!--    配置aop:需要导入aop的约束-->
    <aop:config>
<!--    切入点:express:表达式execution(要切入的位置)-->
        <aop:pointcut id="pointcut" expression="execution(* com.qin.service.UserServiceImpl.*(..))"/>
<!--    切入的具体方法-->
        <aop:advisor advice-ref="before" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

测试

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.add();
    }
}

方式二:自定义切面

导入依赖

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

切入方法

public class DiyPointcut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}

配置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" 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="userService" class="com.qin.service.UserServiceImpl"/>
    <bean id="diy" class="com.qin.diy.DiyPointcut"/>

<!--    方式二:自定义切面-->
    <aop:config>
        <aop:aspect ref="diy">
            <aop:pointcut id="point" expression="execution(* com.qin.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

测试

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.add();
    }
}

方式三:注解

导入依赖

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

切入方法

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotationPointcut {
    @Before("execution(* com.qin.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }
}

注册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" 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="annotation" class="com.qin.diy.AnnotationPointcut"/>
    <bean id="userService" class="com.qin.service.UserServiceImpl"/>
<!--    自动配置代理-->
    <aop:aspectj-autoproxy/>
</beans>

整合Mybatis

导入依赖

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <!--        spring操作数据库需要spring-jdbc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.13</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

编写实体类

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private String pwd;
}

编写mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--类似继承UserDao接口-->
<mapper namespace="com.qin.mapper.UserMapper">
    <!--    实现UserDao里面的方法-->
    <select id="getUser" resultType="user">
       select * from mybatis.user;
    </select>
</mapper>

编写spring-dao.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" 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">

<!--    DataSource:使用spring的数据源替换mybaits的配置
        使用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="123456"/>
    </bean>

<!--    SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
<!--        绑定mybatis核心配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/qin/mapper/*.xml"/>
    </bean>

<!--    SqlSessionTemplate:就是SqlSession-->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器设置sqlSessionFactory-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.qin.mapper.UserMapperImpl">
        <property name="sessionTemplate" ref="sqlSessionTemplate"/>
    </bean>
</beans>

编写UserMapperImpl类

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

import java.util.List;

public class UserMapperImpl implements UserMapper {
    private SqlSessionTemplate sessionTemplate;

    public void setSessionTemplate(SqlSessionTemplate sessionTemplate) {
        this.sessionTemplate = sessionTemplate;
    }

    public List<User> getUser() {
        UserMapper mapper = sessionTemplate.getMapper(UserMapper.class);
        return mapper.getUser();
    }
}

测试

@Test
public void test01(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-dao.xml");
    UserMapper userMapper = classPathXmlApplicationContext.getBean("userMapper", UserMapper.class);
    List<User> users =userMapper.getUser();
    for (User user : users) {
        System.out.println(user);
    }
}

小结

  • spring中可以直接获得SqlSessionFactorybean,并在其中配置文件,代替了Mybatis-config.xml核心配置文件
  • spring中需要UserMapperImpl来使用SqlSessionTemplate的getMapper方法

声明事务

<!--    配置声明事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    结合AOP实现事务的织入-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        设置要给哪些方法配置事务-->
<!--        配置事务的传播特性-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--    配置事务切入-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.qin.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
public List<User> getUser() {
    UserMapper mapper = sessionTemplate.getMapper(UserMapper.class);
    addUser(new User(6,"a","997"));
    deleteUser(4);
    return mapper.getUser();
}

一个方法里的操作将被视为一个事务

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值