Spring

Spring

Spring是轻量级开源框架,可以降低开发应用程序的复杂度,可以集成其他框架,它的核心是控制反转IOC容器和面向切面AOP,控制反转IOC容器底层是xml配置文件 + 工厂模式 + 反射,实现控制反转IOC容器有两个接口,一是BeanFactory,是spring内部成员使用的,二是ApplicationContext,这是BeanFactory的子接口,在BeanFactory的基础上扩展了新的功能,更适合开发人员使用,IOC容器负责两个功能,一个是创建对象和管理对象的生命周期,创建对象有两种方式,一是通过xml配置文件,二是通过注解的方式,另一个是依赖注入,也就是注入属性,有两种方式,一是set方法注入,二是构造器注入,面向切面AOP的功能是在不修改源代码的情况下,对方法添加新的功能,实现AOP有两个动态代理对象,如果实现了接口使用JDK动态代理,如果没有实现接口,使用cglib动态代理,aop有个重要概念,分别是连接点,切入点,通知,切面,连接点是指类中所有需要添加功能的方法,这些方法就是连接点,切入点是类中指实际添功能的方法,这些方法就是切入点,通知是指方法中新添加功能的代码,这些代码就是通知,切面是指将通知添加到方法的过程就是切面

下载springH5的jar包,过程是:

1.进入官网,https://spring.io/,点击右边小猫咪图标
2.找到Access to Binaries描述下的链接
3.找到Downloading a Distribution下的链接https://repo.spring.io/ui/
4.点击左侧Artifacts,找到release下的org下的springframework下的spring
5.复制右侧的url,https://repo.spring.io/artifactory/release/org/springframework/spring/
6.打开下载网址,滑到最下面下载最新版本spring的jar包即可

创建项目,导入五个核心jar包:

在这里插入图片描述

创建实体类,用于测试用spring框架创建对象来调用方法:

public class User {

    public void add(){
        System.out.println("add方法被调用了......");
    }
}

创建spring配置文件,new…找到spring config:

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

    <!--spring通过反射技术创建user对象,并且取名叫user-->
    <bean id="user" class="com.alibaba.User"></bean>
</beans>

创建测试类:

public class UserTset {

    @Test
    public void testAdd(){
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        User user = bean.getBean("user", User.class);
        //3.调用方法
        user.add();
    }
}

---------------------------------------------------------
控制反转IOC容器:

控制反转:将创建对象和管理对象生命周期的权限交给spring管理,目的是为了降低程序的耦合度,提高程序的扩展力
IOC的底层就是对象工厂,底层原理:xml配置文件,工厂模式,反射

IOC实现步骤:

1.xml配置文件配置需要创建的对象
2.创建对象工厂类,通过反射创建对象

spring实现IOC容器的两个接口:

1.BeanFactory,是spring内部使用的接口,开发人员一般不用,这个接口在读取配置文件的时候不会创建配置的对象,在获取对象的时候才创建配置的对象
2.ApplicationContext,是BeanFactory的子接口,扩展了更多的功能,开发人员使用!该接口在读取配置文件的时候就会创建配置的对象

ApplicationContext接口两个实现类:

1.FileSystemXmlApplicationContext,需要传入xml配置文件的全路径
2.ClassPathXmlApplicationContext,只需要传入xml配置文件名xx.xml

IOC操作Bean管理:

1.spring创建对象
2.spring注入属性,DI依赖注入,就是注入属性,spring支持set方法注入和构造器方式注入

Bean管理操作有两种方式:

1.xml配置文件
2.注解

xml方式

实现set方法注入属性:

编写类,属性,提供set方法

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

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

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

配置spring config配置文件

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

    <!--spring通过反射技术创建user对象,并且取名叫user-->
    <bean id="user" class="com.alibaba.User">
        <!--注入属性前,必须先配置要创建的对象-->
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

测试结果

public class UserTset {

    @Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        User user = bean.getBean("user", User.class);
        System.out.println(user);
    }
}

--------------构造器方式注入--------------------

创建对象,提供属性构造器

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

    //构造器方式注入
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

配置spring config配置文件

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

    <!--spring通过反射技术创建user对象,并且取名叫user-->
    <bean id="user" class="com.alibaba.User">
        <!--注入的是全参构造器赋值-->
        <constructor-arg name="name" value="李四"></constructor-arg>
        <constructor-arg name="age" value="19"></constructor-arg>
    </bean>
</beans>

测试结果

public class UserTset {

    @Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        User user = bean.getBean("user", User.class);
        System.out.println(user);
    }
}

----------------属性是null值或者含有其他特殊符号-----------------

spring config配置文件赋值是null或含有其他特殊符号处理方法:

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

    <!--spring通过反射技术创建user对象,并且取名叫user-->
    <bean id="user" class="com.alibaba.User">
        <!--注入的是全参构造器赋值-->
        <property name="name">
            <!--赋值为null-->
            <null/>
        </property>
        <property  name="age">
            <!--想要属性包含特殊符号,比如<>-->
            <!--方式1:用转义方法,比如&gt;表示大于,&lt;表示小于-->
            <!--方式2:用语法,<![CDATA[内容]]>-->
            <value>
                <![CDATA[19]]>
            </value>
        </property>
    </bean>
</beans>

-------------------注入外部bean----------------------

定义dao层接口

package com.alibaba.dao;

public interface UserDao {

    public void method();
}

定义dao层接口实现类

public class UserDaoImpI implements UserDao {

    public void method() {
        System.out.println("UserDaoImpI implements method!!!");
    }
}

定义业务层service类,引入外部bean

public class UserService {

    //注入外部bean属性
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void methode(){
        System.out.println("UserService method!!!");
        userDao.method();
    }
}

配置spring config配置文件

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

    <bean id="userDaoImpI" class="com.alibaba.dao.UserDaoImpI"></bean>
    <bean id="userService" class="com.alibaba.service.UserService">
        <!--ref:表示引入其他对象,这里是UserDaoImpI对象的ID-->
        <property name="userDao" ref="userDaoImpI"></property>
    </bean>
</beans>

测试结果

 @Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        UserService userService = bean.getBean("userService", UserService.class);
        userService.methode();
    }

--------------------注入内部Bean------------------------

创建部门类

public class Dept {

    private String dname;//部门名
    public void setDname(String dname) {
        this.dname = dname;
    }

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

创建员工类

public class Emp {
    private String name;//员工名
    private int age;//员工年龄
    private Dept dept;//引入部门类
    public void setDept(Dept dept) {
        this.dept = dept;
    }

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

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

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

spring config配置文件

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

    <bean id="emp" class="com.alibaba.bean.Emp">
        <property name="name" value="张三"></property>
        <property name="age" value="20"></property>
        <property name="dept" >
            <!--内部Bean-->
            <bean id="dept" class="com.alibaba.bean.Dept">
                <property name="dname" value="无垢者"></property>
            </bean>
        </property>
    </bean>
</beans>
-------------------------------------------
还可以使用级联方式:外部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="emp" class="com.alibaba.bean.Emp">
        <property name="name" value="张三"></property>
        <property name="age" value="20"></property>
        <property name="dept" ref="dept"></property>
    </bean>
    <!--外部Bean-->
    <bean id="dept" class="com.alibaba.bean.Dept">
        <property name="dname" value="无垢者"></property>
    </bean>
</beans>

测试结果

public class UserTset {

    @Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        Emp emp = bean.getBean("emp", Emp.class);
        System.out.println(emp);
    }
}

-------------注入集合---------------------

创建类,属性是集合,提供set方法和toString

public class Controller {
    private String[] arr;
    private List<String> list;
    private Set<String> set;
    private Map<String,String> map;

    public void setArr(String[] arr) {
        this.arr = arr;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public String toString() {
        return "Controller{" +
                "arr=" + Arrays.toString(arr) +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                '}';
    }
}

spring config配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--约束文件-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置需要创建的对象-->
    <bean id="controller" class="com.alibaba.Controller">
        <!--赋值数组-->
        <property name="arr">
            <array>
                <value>arr1</value>
                <value>arr2</value>
            </array>
        </property>
        <!--赋值List集合-->
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        <!--赋值Set集合-->
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>
        <!--赋值Map集合-->
        <property name="map">
            <map>
                <entry key="1号" value="张三"></entry>
                <entry key="2号" value="李四"></entry>
            </map>
        </property>
    </bean>
</beans>

测试结果

 @Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        Controller controller = bean.getBean("controller", Controller.class);
        System.out.println(controller);
    }

-------------注入的集合,存储的值是对象----------------------

创建类

public class Collection_Bean {
    private List<User> users;

    public void setUsers(List<User> users) {
        this.users = users;
    }

    @Override
    public String toString() {
        return "Collection_Bean{" +
                "users=" + users +
                '}';
    }
}

spring config配置文件

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

    <!--注入集合,存储的是对象-->
    <bean id="collection_bean" class="com.alibaba.bean.Collection_Bean">
        <property name="users">
            <list>
                <!--引入外部bean对象-->
                <ref bean="user"></ref>
            </list>
        </property>
    </bean>
    <bean id="user" class="com.alibaba.User">
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

测试结果

 @Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        Collection_Bean collection_Bean = bean.getBean("collection_bean", Collection_Bean.class);
        System.out.println(collection_Bean);
    }

-------------将集合注入部分提取出来------------------

1.增加新的约束文件内容,复制一份xmlns=“http://www.springframework.org/schema/beans”
修改成xmlns:util=“http://www.springframework.org/schema/util”
复制一份 xsi:schemaLocation,将所有beans改成util
“http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd”>
最终结果如下:

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

2.通过util标签完成list集合注入的提取

<!--提取list集合注入的属性-->
    <util:list id="user">
        <!--如果是对象,用<ref bean=""></ref>-->
        <value>张三</value>
    </util:list>

完整顺序:

创建类

public class Collection_Bean {
    private List<String> name;

    @Override
    public String toString() {
        return "Collection_Bean{" +
                "name=" + name +
                '}';
    }

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

spring config配置文件

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

    <!--提取list集合注入的属性-->
    <util:list id="user">
        <!--如果是对象,用<ref bean=""></ref>-->
        <value>张三</value>
    </util:list>
    <bean id="collection_bean" class="com.alibaba.bean.Collection_Bean">
        <property name="name" ref="user"></property>
    </bean>
</beans>

测试结果

@Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        Collection_Bean collection_Bean = bean.getBean("collection_bean", Collection_Bean.class);
        System.out.println(collection_Bean);
    }

------------------------------------------------------------
IOC操作Bean管理

有两种类型Bean,一种的普通bean,一种是工厂bean
普通bean:spring config配置文件定义的类就是返回值的类型
工厂bean:config配置文件定义的类返回值类型可以不一样

工厂bean步骤:

1.创建类,让类作为工厂bean,实现接口FactoryBean,泛型约束类型
2.实现接口的方法,定义getObject方法返回值为泛型约束类型

创建类,实现FactoryBean接口

public class MyBean implements FactoryBean<User> {
    /**
     * 返回值类型可以改变
     * @return
     * @throws Exception
     */
    public User getObject() throws Exception {
        User user = new User();
        user.setName("张三");
        user.setAge(18);
        return user;
    }

    public Class<?> getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return false;
    }
}

spring config配置文件

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

    <bean id="myBean" class="com.alibaba.bean.MyBean"></bean>
</beans>

测试结果

@Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        User myBean = bean.getBean("myBean", User.class);
        System.out.println(myBean);
    }

-----------------------------------------------------
bean的作用域:

spring默认是单实例,可以设置成多实例

将pring默认单实例改成多实例:

加属性scope=prototype即可
如果是单实例,在读取配置文件就会创建对象
如果是多实例,在读取配置文件不会创建对象,而是调用getBean的时候创建多实例对象

bean生命周期:

1.执行无参构造器创建bean实例
2.调用set方法赋值
3.将bean实例传递给后置处理器的方法
4.执行初始化方法,需要配置
5.将bean实例传递给后置处理器的方法
6.获取创建好的bean实例
7.执行销毁方法,需要配置

代码演示bean生命周期:

创建类

public class MyBean  {

    private String name;

    public MyBean() {
        System.out.println("第一步,执行无参构造器创建bean实例");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("第二步,调用set方法为属性赋值");
    }

    public void initMethod(){
        System.out.println("第四步,执行初始化方法");
    }

    public void destroyMethod(){
        System.out.println("第七步,执行销毁方法");
    }
}

后置处理器实现类:

public class BeanPostProcessorImpI implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第3步,初始化之前执行的后置处理器方法");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第5步,初始化之后执行的后置处理器方法");
        return bean;
    }
}

spring config配置文件

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

    <!--init-method:配置初始化方法,destroy-method配置销毁方法-->
    <bean id="myBean" class="com.alibaba.lifecycle.MyBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="张三"></property>
    </bean>

    <!--配置后置处理器:会对所有bean生效-->
    <bean id="beanPostProcessorImpI" class="com.alibaba.lifecycle.BeanPostProcessorImpI"></bean>
</beans>

测试类

@Test
    public void testAdd() {
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取配置创建的对象
        MyBean myBean = bean.getBean("myBean", MyBean.class);
        System.out.println("第六步,获取创建好的bean实例");
        //最后需要手动销毁
        myBean.destroyMethod();
    }

--------------------------属性自动装配--------------------------------

主要是配置文件的改变,byName表示id属性名必须和注入的属性名相同,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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="dept" class="com.alibaba.bean.Dept">
        <property name="dname" value="杀神部"></property>
    </bean>
    <!--autowire:spring根据属性名进行自动装配,要求:id属性名必须和注入的属性名相同-->
    <bean id="emp" class="com.alibaba.bean.Emp" autowire="byName">
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

----------------------------------------------------
引入外部属性文件,比如数据库连接信息:
1.添加约束文件的命名空间

xmlns:context="http://www.springframework.org/schema/context"以及http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

2.使用标签,引入外部属性文件

<context:property-placeholder location=“dataSource.properties”></context:property-placeholder>

3.配置需要创建的对象,引入第三方jar包的对象,省略不做…

使用${属性配置文件的key}赋值
这样只需要修改属性配置文件,spring config配置文件不需要修改!

注解

注解是代码特殊标记,可以简化xml配置

创建对象的注解有四个:

@Component,@Controller,@Service,@Repository

基于注解完成对象创建的步骤:

1.添加aop依赖jar包
2.引入约束文件的名称空间,配置组件扫描
3.创建类
4.创建测试类

1.添加aop依赖jar包,spring其他核心依赖也需要,否则无法修改约束文件

<!--AOP依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.16</version>
        </dependency>

2.引入约束文件的名称空间,配置组件扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置组件扫描-->
    <context:component-scan base-package="com.alibaba.spring5"></context:component-scan>
</beans>

3.创建类

package com.alibaba.spring5.service;

import org.springframework.stereotype.Component;
//创建对象注解的(value = "user")可以省略不写,对象引用默认是类名首字母小写
//如果想取名,value属性可以省略,直接写@Component("xxx")
@Component(value = "user")
public class User {

    public void method(){
        System.out.println("method方法执行了!");
    }
}

4.创建测试类

 @Test
    public void testMethod(){
        //1.读取配置文件,创建对象
        ApplicationContext bean = new ClassPathXmlApplicationContext("springannotation.xml");
        //2.获取创建好的对象
        User user = bean.getBean("user", User.class);
        //3.调用方法测试结果
        user.method();
    }

在这里插入图片描述--------------------------------------------------------------------
基于注解方式实现属性注入

@AutoWired:根据属性类型自动装配
@Qualifier:根据属性名注入,必须联合AutoWired使用,当注入的接口属性有多个实现类,用来指定注入的对象!
@Resource:根据类型注入,也可以根据属性名注入
以上三个是针对对象类型的属性注入
@Value:是对普通属性的注入

创建持久层接口:

public interface UserDao {
    public void method();
}

创建接口实现类:

@Repository
public class UserDaoImp implements UserDao {
    public void method() {
        System.out.println("我是UserDao实现类的方法!");
    }
}

创建业务层类,注入对象属性:

@Component
public class UserService {

    @Autowired
    private UserDao userDao;//多态,相当于 UserDao userDao = new UserDaoImp();

    public void method(){
        System.out.println("method方法执行了!");
        //调用方法
        userDao.method();
    }
}

测试结果:

@Test
    public void testMethod(){
        //1.读取配置文件,创建对象
        ApplicationContext bean = new ClassPathXmlApplicationContext("springannotation.xml");
        //2.获取创建好的对象
        UserService user = bean.getBean("user", UserService.class);
        //3.调用方法测试结果
        user.method();
    }

测试QUA注解:

@Component
public class UserService {

    @Autowired
    @Qualifier("userDaoImp")//注入对象名为userDaoImp的对象
    private UserDao userDao;//多态,相当于 UserDao userDao = new UserDaoImp();

    public void method(){
        System.out.println("method方法执行了!");
        //调用方法
        userDao.method();
    }
}

测试Resource注解:它是javax包下扩展的,不属于spring的,虽然也能做到相同的注入功能,但是spring推荐使用自家的产品

@Component
public class UserService {

    //@Resource//根据对象类型注入
    @Resource(name = "userDaoImp")//根据对象名注入
    private UserDao userDao;//多态,相当于 UserDao userDao = new UserDaoImp();

    public void method(){
        System.out.println("method方法执行了!");
        //调用方法
        userDao.method();
    }
}

测试Value注解:

 //@Value(value = "张三")
    @Value("张三")
    private String name;//用注解注入普通属性

-----------------------------------------------
完全用注解开发

第一步:创建配置类

@Configuration//表示这是一个配置类
@ComponentScan(basePackages = "com.alibaba.spring5")//表示扫描该包下所有对象
public class SpringConfig {
}

第二步,将扫描配置文件对象修改成配置类对象,测试结果

 @Test
    public void testMethod(){
        //1.创建注解类读取配置类
        ApplicationContext bean = new AnnotationConfigApplicationContext(SpringConfig.class);
        //2.获取创建好的对象
        UserService user = bean.getBean("userService", UserService.class);
        //3.调用方法测试结果
        user.method();
    }

AOP

AOP面向切面:

在不修改源代码的情况下,添加新的功能,降低程序的耦合度,提高程序的扩展性

AOP底层原理:

使用了动态代理,有两种动态代理方式
1.有接口的情况,使用了JDK动态代理,创建了接口实现类的代理对象,增加新的功能
2.没有接口的情况,CGLIB动态代理,创建子类代理对象,增加新的功能

JDK动态代理底层原理实现过程:

定义接口

public interface UserDao {
    public int method(int a,int b);
}

定义接口实现类

public class UserDaoImp implements UserDao {
    public int method(int a, int b) {
        System.out.println("我是UserDao实现类的方法!");
        return a + b;
    }
}

使用JDK动态代理,为对象的方法增加新的功能

//JDK代理类
public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类代理对象
        Class[] interfaces = {UserDao.class};
        UserDaoProxy userDaoProxy = new UserDaoProxy(new UserDaoImp());
        UserDao o = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(), interfaces, userDaoProxy);
        int result = o.method(1, 2);
        System.out.println("result = " + result);
    }
}

//创建代理对象的代码
class UserDaoProxy implements InvocationHandler {

    //需要将被代理的对象传递过来,通俗的说就是哪个对象的方法需要增加新的功能,传递过来
    //使用构造器传递
    private Object obj;//用Object的目的是:多态,更通用

    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }


    //增加功能的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //新增的功能在方法之前
        System.out.println("新增的功能在方法之前!");

        //执行新增的方法
        Object invoke = method.invoke(obj, args);

        //新增的功能在方法之前
        System.out.println("新增的功能在方法之后!");

        return invoke;
    }
}

-------------------------------------------------------
AOP的术语概念:

连接点:类中可以增加功能的方法,这些方法就是连接点
切入点:实际被增加功能的方法,这些方法就是切入点
通知:方法中实际增加功能的部分逻辑就是通知,通知有多种类型,分别是:前置通知,后置通知,环绕通知,异常通知,最终通知
切面:是一个动作,将通知加入切入点的过程

Spring框架一般是基于AspectJ实现AOP操作:

AspectJ:是独立框架,不属于Spring,只是联合使用进行AOP操作
AspectJ实现AOP有两种方式:1.xml配置文件2.注解

添加依赖
在这里插入图片描述切入点表达式:

语法结构:
execution(权限修饰符,返回值类型,全类名,方法名(参数列表))
例子1:需要对com.alibaba.spring5.service.User类下的method方法增加新的功能
execution(* com.alibaba.spring5.service.User.method(…))
解释:表示通用返回值类型,中间有个空格,权限修饰符可以省略不写,点点表示参数
例子2:需要对com.alibaba.spring5.service.User类下的所有方法增加新的功能
execution(
com.alibaba.spring5.service.User.(…))
例子3:需要对com.alibaba.spring5.servicer包下的所有类的所有方法增加新的功能
execution(
com.alibaba.spring5.service.*.*(…))

进行通知的配置:

1.在spring config配置文件中添加新的约束,开启注解扫描

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

    <!--开启组件扫描-->
    <context:component-scan base-package="com.alibaba.spring5.aopanno"></context:component-scan>
</beans>

2.使用注解创建User和UserProxy对象

//被增强类
@Component
public class User {
    public void method() {
        System.out.println("method方法执行了!");
    }
}
-------------------------------
//增强类
@Component
public class UserProxy {
    //在方法执行前,增加了新的功能
    public void before() {
        System.out.println("before方法执行了......");
    }
}

3.在增强类上面添加注解Aspect

//增强类
@Component
@Aspect//生成代理对象
public class UserProxy {
    //在方法执行前,增加了新的功能
    public void before() {
        System.out.println("before方法执行了......");
    }
}

4.spring文件中开启生成代理对象

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

    <!--开启组件扫描-->
    <context:component-scan base-package="com.alibaba.spring5.aopanno"></context:component-scan>
    <!--开启Aspect生成代理对象:如果类上有Aspect注解,就生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

5.配置不同类型的通知

//增强类
@Component
@Aspect//生成代理对象
public class UserProxy {
    //在方法执行前,增加了新的功能
    @Before(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
    public void before() {
        System.out.println("before方法执行了......");
    }

    //最后输出
    @AfterThrowing(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
    public void afterThrowing() {
        System.out.println("AfterThrowing方法执行了......");
    }

    //倒数第二输出,如果发生异常,则不输出
    @AfterReturning(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
    public void afterReturning() {
        System.out.println("AfterReturning方法执行了......");
    }

    //倒数第三输出
    @After(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
    public void after() {
        System.out.println("After方法执行了......");
    }

    //环绕通知:在方法的最开始以及方法的最后(最后一个)
    @Around(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Around方法执行了......");
        proceedingJoinPoint.proceed();//执行被增强的类方法
        System.out.println("Around方法执行了......");
    }
}

测试结果

@Test
    public void testMethod(){
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean1.xml");
        //2.获取创建好的对象
        User user = bean.getBean("user", User.class);
        //3.调用方法测试结果
        user.method();
    }

提取切入点表达式,作为公共的使用

//增强类
@Component
@Aspect//生成代理对象
public class UserProxy {

    //提取切入点表达式
    @Pointcut(value = "execution(* com.alibaba.spring5.aopanno.User.method(..))")
    public void common(){}

    //在方法执行前,增加了新的功能
    @Before(value = "common()")
    public void before() {
        System.out.println("before方法执行了......");
    }

    //在被增强的方法之后,有异常才输出
    @AfterThrowing(value = "common()")
    public void afterThrowing() {
        System.out.println("AfterThrowing方法执行了......");
    }

    //在被增强的方法之后,如果发生异常,则不输出
    @AfterReturning(value = "common()")
    public void afterReturning() {
        System.out.println("AfterReturning方法执行了......");
    }

    //在有无异常之后,最后环绕之前,如果有异常,最后环绕则不输出
    @After(value = "common()")
    public void after() {
        System.out.println("After方法执行了......");
    }

    //环绕通知:在最开头输出一次,最结尾输出一次,如果有异常,最后一次则不输出
    @Around(value = "common()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Around方法执行了......");
        proceedingJoinPoint.proceed();//执行被增强的类方法
        System.out.println("Around方法执行了......");
    }
}

有多个增强类对同一个方法进行增加新的功能,设置增强类的优先级:

使用@Order注解设置优先级,数字越小,优先级越高

//增强类
@Component
@Aspect//生成代理对象
@Order(1314)
public class PersonProxy {

    //提取切入点表达式
    @Pointcut(value = "execution(* com.alibaba.spring5.aopanno.User.method(..))")
    public void common(){}

    //在方法执行前,增加了新的功能
    @Before(value = "common()")
    public void before() {
        System.out.println("PersonProxy  ==>  before方法执行了......");
    }
}

完全注解开发

创建配置类,不需要xml配置文件

@Configuration//表示这是一个配置类
@ComponentScan(basePackages = "com.alibaba.spring5")//表示扫描该包下所有对象
@EnableAspectJAutoProxy(proxyTargetClass = true)//扫描代理对象注解
public class SpringConfig {
}

------------------------------------------------------
基于配置文件完成AOP

创建被增强类和增强类

//被增强类
public class Student {

    //被增强方法
    public void method(){
        System.out.println("被增强方法执行了......");
    }
}
------------------------------------------------
//增强类
public class StudentProxy {

    //增强方法
    public void method(){
        System.out.println("增强方法执行了......");
    }
}

配置spring config文件

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

    <!--配置需要创建的对象-->
    <bean id="student" class="com.alibaba.spring5.aopxml.Student"></bean>
    <bean id="studentProxy" class="com.alibaba.spring5.aopxml.StudentProxy"></bean>

    <!--配置aop增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* com.alibaba.spring5.aopxml.Student.method(..))"/>
        <!--配置切面-->
        <aop:aspect ref="studentProxy">
            <!--增强新的功能-->
            <aop:before method="method" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>

</beans>

测试结果

@Test
    public void testMethod(){
        //1.读取配置文件
        ApplicationContext bean = new ClassPathXmlApplicationContext("bean1.xml");
        //2.获取创建好的对象
        Student student = bean.getBean("student", Student.class);
        //3.调用方法测试结果
        student.method();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值