Spring IOC AOP部分笔记

自己学习Spring5整理的笔记

Spring学习过程

IOC部分

1构建一个HelloSpring

1.1构建步骤

在java文件夹中创建Java文件

在resources中创建beans.xml 即容器

在容器中进行配置 在IDEA中可以直接在XML Config下找到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来创建对象,在Spring中这些都称为Bean
    Bean相当于 对象 = new 类名();

    id = 变量名
    class = new的对象
    property 相当于给对象中的属性设置一个值
-->
    <bean id="hello" class="HelloSpring">
        <!--hello是一个对象,借助了class,在下面的property中给这个类的变量赋值就行-->
    <property name="str" value="Spring"/>

    </bean>
</beans>

在mytest中进行使用

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

public class MyTest {
    public static void main(String[] args) {
        //获取Spring的上下文对象 即容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//选定容器
        //我们的对象现在都在Spring中管理了,我们要使用,就直接去里面取
        HelloSpring hello = (HelloSpring) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

这一整个过程就叫做控制反转:

控制:由Spring来控制创建

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

依赖注入:用set方法进行注入,若删除setStr就会报错

这就是IOC(控制反转)

2 IOC创建对象方式

1.调用了无参构造方法 就可以建立一个普通的对象

2.若定义了有参的构造方法,就需要以下方法去解决

​ 1.下标赋值

    <!--1.下标赋值--> 
<bean id="User" class="User">
        <constructor-arg index="0" value="ZYB"/>
    </bean>

​ 2.类型赋值

    <!--不建议使用2.赋类型值 若是在基本类型中type就为其类型,引用类型就用java.lang.String-->
    <bean class="User" id="User">
        <constructor-arg type="java.lang.String" value="zyb">
        </constructor-arg>
    </bean>

​ 3.直接通过参数名来设置 最常使用

	<!--3.直接通过参数名来构造-->
    <bean id="User" class="User">
        <constructor-arg name="name" value="Zyb"/>
    </bean>

需要注意的是,在Spring初始化的时候,就已经把容器初始化了。即无参构造方法都会被调用

3 Spring配置说明

3.1别名

即前面的name可用alias后面的别名替换 但二者均可使用

<alias name = "User" alias = "abcd"/>

3.2 bean的配置

其中name就相当于是别名

class是其全限定名:包名+类型

<bean id = "User" class = "User" name = "uuser,u1,u2,u3">

3.3 import

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

下列代码就将beans和bean2合并成一个配置文件

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

<import resource="bean2.xml"/>
</beans>

4 DI 依赖注入

4.1 set注入

依赖:bean对象的创建依赖于容器

注入:bean对象的所有属性,由容器来注入

首先写好实体类

//Address
public class Address {
    public String address;

    public String getAddress() {
        return address;
    }

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

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
//Student
import java.util.*;

public class Student {

    private String name;
    private Address address;
    private String[] book;
    private List<String> hobbies;
    private Map<String, String> card;
    private Set<String> games;
    private Properties info;
    private String wife;

    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[] getBook() {
        return book;
    }

    public void setBook(String[] book) {
        this.book = book;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    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 Properties getInfo() {
        return info;
    }

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

    public String getWife() {
        return wife;
    }

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

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

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="address" class="Address">
        <property name="address" value="绍兴"/>
    </bean>
    <bean id="student" class="Student">
    <!--1.普通值注入,直接使用value-->
        <property name="name" value="ZYB"/>
        <!--2.bean注入,直接使用ref-->
        <property name="address" ref="address"/>
        <!--3.数组注入-->
        <property name="book">
            <array>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>西游记</value>
                <value>三国演义</value>
            </array>
        </property>
        <!--4.List注入-->
        <property name="hobbies">
            <list>
                <value>听歌</value>
                <value>敲代码</value>
                <value>看电影</value>
            </list>
        </property>
        <!--5.Map注入-->
        <property name="card">
            <map>
                <entry key="身份证" value="111111222222223333"/>
                <entry key="银行卡" value="123123123"/>
            </map>
        </property>
        <!--6.set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>

        <!--7.null值注入-->
        <property name="wife">
            <null/>
        </property>
        <!--8.Properties注入-->
        <property name="info">
            <props>
                <prop key="姓名">小明</prop>
                <prop key="学号">2012190535</prop>
                <prop key="性别"></prop>
            </props>
        </property>
    </bean>
</beans>

4.2构造方法注入

1.需要在方法中构建带参构造方法

2.用constructor-arg进行信息输入

4.3 c命名空间和p命名空间注入

使用前都要添加相关的xml文件 需要构造一个实体类

都是可以直接注入属性值的方法

都是用set方法注入


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

        public User() {
        }

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        public int getAge() {
            return age;
        }

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

        public String getName() {
            return name;
        }

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

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


xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

p命名空间注入是通过set方法注入

<bean id="user" class="User" p:name="zyb" p:age="18"/>

c命名空间是通过构造器注入,需要在对应类中构造有参和无参构造方法才可执行

<bean id="user" class="User" c:name="zyb" c:age="18"/>

4.4 内部bean、外部bean和级联赋值

外部bean:直接在beans标签内部直接定义的bean对象,外部bean可以被多个bean对象引用

内部bean:在某个bean标签的内部定义的bean对象,内部bean只能被某个对象的某个属性引用。

实现类代码
package pojo;

import dao.Def;

public class User {

    public Def def;
    private String uname;

    public void setUname(String uname) {
        this.uname = uname;
    }

    public void setDef(Def def) {
        this.def = def;
    }

    public void out(){
        System.out.println("My name is" + uname);
    }

    @Override
    public String toString() {
        return "User{" +
                "def=" + def +
                ", uname='" + uname + '\'' +
                '}';
    }
}
package dao;

public class Def {

    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    public void oout(){
        System.out.println("this company is broken");
    }
}
外部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="user" class="pojo.User">
        <property name="uname" value="ZYB"/>
        <property name="def" ref="def"/>
    </bean>
    <bean id="def" class="dao.Def">
    </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"
       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 https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="user" class="pojo.User">
        <property name="uname" value="ZYB"/>
        <property name="def">
            <bean id="def" class="dao.Def">

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

    <bean id="user" class="pojo.User">
        <property name="uname" value="ZYB"/>
        <property name="def" ref="def"/>
    </bean>
    <bean id="def" class="dao.Def">
        <property name="dname" value="商务部"/>
    </bean>
</beans>

4.5工厂bean

实现类

即虽然我们定义的是User类的bean,但是当User实现了 FactoryBean接口,并且在其中实现getObject方法,就可以在Test中定义getObject方法中返回类型的对象。

package dao;

public class Def {

    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    public void oout(){
        System.out.println("this company is broken");
    }
}
package pojo;

import dao.Def;
import org.springframework.beans.factory.FactoryBean;

public class User implements FactoryBean<Def> {

    public Def def;
    private String uname;

    public void setUname(String uname) {
        this.uname = uname;
    }

    public void setDef(Def def) {
        this.def = def;
    }

    public void out(){
        System.out.println("My name is" + uname);
    }

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

    @Override
    public Def getObject() throws Exception {
        return def;
    }

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

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

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="pojo.User">
        <property name="uname" value="ZYB"/>
        <property name="def" ref="def"/>
    </bean>
    <bean id="def" class="dao.Def">
        <property name="dname" value="商务部"/>
    </bean>
</beans>

4.6 Bean的作用域

Bean有六种作用域

在这里重点解释singleton和prototype两种

4.6.1 singleton

即单例,我们对于每一个bean,都只能建立一个实例

在Java中,都是隐式的默认单例

package com.example.spring03;

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");

        User user = (User) context.getBean("user");
        User user2 = (User) context.getBean("user");

        System.out.println(user == user2);
    }
}
//结果为true

我们可以在bean的末尾加入scope来将隐式转为显式

<bean id="user" class="com.example.spring03.User" scope="singleton">
4.6.2prototype

即原型模式,每个引用都会指向一个新的对象

需要在末尾改变scope使其变为原型模式

<bean id="user" class="com.example.spring03.User" scope="prototype">

5 Bean的自动装配

自动装配使Spring满足bean依赖的一种方式

Spring会在上下文中自动寻找并自动给bean装配属性

Spring中有三种装配方式

1.在xml中显示的配置

2.在Java中显示配置

3.隐式的自动装配bean

5.1byName

会自动在容器上下文中查找,和自己对象方法后面的值对应的bean id

但一旦id名乱取,就无法使用

    <bean id="people" class="pojo.People" autowire="byName">

5.2byType

会自动在容器上下文中查找,和自己对象属性类型相同的bean

但一旦id名的类型(class)一致,就无法使用

但byType甚至可以取消id进行使用

    <bean id="people" class="pojo.People" autowire="byType">

5.3 使用注解实现自动装配

5.3.1 什么是注解

1.注解是代码中的特殊标记,格式是@注解名称(属性名称=属性值,属性名称=属性值…)

2.注解作用在类,方法,属性上面

3.使用注解的目的是让xml配置更加简洁,更加优雅

5.3.2 Spring针对Bean管理中创建对象提供注解

@Component

@Service

@Controller

@Repository

*上面四个注解功能是一样的,都可以用来创建bean实例

5.3.3 基于注解方式实现对象创建
第一步 引入aop依赖
第二步 开启组件扫描

引入contex约束 配置注解支持

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

开启组件扫描

<context:component-scan base-package="dao">
    </context:component-scan>
    <context:component-scan base-package="pojo">
    </context:component-scan>
<!--多个包也可写成如下方法-->
<context:component-scan base-package="dao,pojo">
    </context:component-scan>
<!--也可写成上层目录-->
创建类,在类上面添加创建对象注解

以@Component(value = “xxx”)为例

其作用相当于自动创建了一个bean

注解中的value可以省略,不写的话就默认为类的名称首字母小写

package service;

import org.springframework.stereotype.Component;

//注解中的value可以省略,不写的话就默认为类的名称首字母小写
@Component(value = "userService") //等价于 <bean id="userService" class="..."/>
public class UserService {

    public void add(){
        System.out.println("Service add....");
    }
}
5.3.4 扫描配置问题

常规扫描,即会扫描该包中所有的注解 若有多个包,就需要用,隔开

    <context:component-scan base-package="pojo"/>

非常规扫描 表示只扫描注解类中的Controller

<context:component-scan base-package="pojo" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

非常规扫描 表示不扫描注解中的Controller

<context:component-scan base-package="pojo">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
5.3.5 基于注解方式实现属性注入

@Autowired:根据属性类型进行自动装配

1.把service和dao的对象都进行创建,在service和dao类添加创建对象注解

2.在service中注入dao对象,在service类中添加dao类型属性,在属性上面使用注解

实现类代码:

package dao;


import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{

    @Override
    public void add() {
        System.out.println("dao add");
    }
}
package service;

import dao.UserDao;
import dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

//注解中的value可以省略,不写的话就默认为类的名称首字母小写
@Service(value = "userService") //等价于 <bean id="userService" class="..."/>
public class UserService {

    @Autowired//根据类型进行注入
    //不需要添加set方法
    private UserDaoImpl userDaoImpl;

    public void add(){
        System.out.println("Service add....");
        userDaoImpl.add();
    }
}

测试类代码:

package service;

import dao.UserDao;
import dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

//注解中的value可以省略,不写的话就默认为类的名称首字母小写
@Service(value = "userService") //等价于 <bean id="userService" class="..."/>
public class UserService {

    @Autowired//根据类型进行注入
    //不需要添加set方法
    private UserDaoImpl userDaoImpl;

    public void add(){
        System.out.println("Service add....");
        userDaoImpl.add();
    }
}

@Qualifier:根据属性名称进行注入

需要和@Autowired一起配合使用

比如,一个接口有多个实现类对象,若用@Autowired来进行注入,就会导致错误,因为是相同类型无法找到对应的实现类,而若用@Qualifier进行注入,则可以通过value注明到底是哪个实现类

@Resource:既可以根据属性类型注入,也可以根据属性名称注入,默认根据属性名称

JDK11之后就不可使用了,是属于JDK的注解而非Spring,因此JDK不支持后就不再可以使用了

以上三者都是对对象进行注入

@Value:注入普通类型

	@Value(value = "zyb")
    private String name;
    
    @Value(value = "18")
    private int old;
5.3.6 完全注解开发

1.创建配置类,替代xml配置文件

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import pojo.User;

@Configuration//把当前类作为配置类,替代xml文件
@ComponentScan(basePackages = {"config","dao"})//类似原先xml文件中的scan
public class Myconfig {

    @Bean //只写在方法上,返回值是一个对象 类名相当于id,返回值类型相当于class
    public User getUser(){

        return new User();
    }

}

2.编写测试类

package com.example.spring08;

import config.Myconfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import pojo.User;

public class Mytest {
    public static void main(String[] args) {
        //加载配置类
        ApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
        //其余步骤与前面都相同
        User getUser = (User) context.getBean("getUser");//bean的名字就是方法的名字相当于id
        System.out.println(getUser.getName());
    }
}
5.3.7 小结

xml用于管理bean

注解只用于属性的注入即可

需要加入配置

AOP部分

1 AOP的概念

1.1面向切面编程(面向方面编程)

可以进一步对业务逻辑进行隔离,从而使得业务逻辑个部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。即不通过修改源代码就可以产生新的功能。

1.2底层原理

AOP底层使用了动态代理

1.2.1 有接口的情况

JDK中的动态代理

具体过程

1.使用Proxy类里面的方法创建代理对象

2.调用newProxyInstance方法 其中有三个参数

public static Object newProxyInstance
    (ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

第一个参数 是一个类加载器

第二个参数 增强方法所在的类,这个类实现的接口,支持多个接口

第三个参数 实现这个接口InvocationHandler,创建代理对象,写增强的方法

编写JDK动态代理代码

1.创建接口,定义方法

package com.example.spring08;

public interface UserDao {

    public int add(int a, int b);

    public String update(String id);
}

2.创建接口的实现类,实现方法

package com.example.spring08;

public class UserDaoImpl implements UserDao{

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

实现Proxy内的newProxyInstance方法

package com.example.spring08;

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

public class JDKProxy {

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

class UserDaoProxy implements InvocationHandler{

    //1.把创建的是谁的代理对象,把那个谁传递过来
    //通过有参构造进行传递

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

    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前
        System.out.println("方法之前执行...."+method.getName()+":传递的参数..."+ Arrays.toString(args));

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

        //方法之后
        System.out.println("方法之后执行..."+obj);

        return null;
    }
}
1.2.2没有接口的情况

CGLIB的动态代理

1.3 AOP操作术语

1.连接点

类中可以被增强的方法就称为连接点

2.切入点

类中实际被真正增强的方法就称为切入点

3.通知(增强)

实际被增强的逻辑部分称为通知

通知有多种类型

1.前置通知:在方法之前执行

2.后置通知:在方法之后执行

3.环绕通知:在方法的前面和后面都做执行

4.异常通知:方法出现异常时执行

5.最终通知:无论什么情况都会执行 类似finally

4.切面

把通知应用到切入点的过程就称为切面 是一个动作

1.4 准备工作

在Spring框架中,一般基于AspectJ实现AOP操作

1.AspectJ不是Spring的组成部分,是独立的AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

基于AspectJ实现AOP操作

(1)基于xml配置文件实现

(2)基于注解方式实现 (使用较多)

在项目工程中引入AOP相关的依赖
切入点表达式

(1)切入点表达式的作用:知道要对哪个类里面的哪个方法进行增强

(2)语法结构:

execution([权限修饰符] [返回类型] [类的全路径] [方法名称]([参数列表]))

示例1:对com.atguigu.dao.BookDao的add方法进行增强

execution(* com.atguigu.dao.BookDao.add(…) ) *代表任意路径 返回类型忽略 参数列表用…代替

示例2:对com.atguigu.dao.BookDao的所有方法进行增强

execution(* com.atguigu.dao.BookDao.*(…) ) 代表对类中的所有方法进行增强

示例3:对com.atguigu.dao.BookDao的所有类,所有方法进行增强

execution(* com.atguigu.dao..(…) )

2 AspectJ注解

1.创建类,在类里面定义方法
package aopanno;

//被增强的类
public class User {
    public void add(){
        System.out.println("add......");
    }
}
2.创建增强类

1.在增强类里面,创建方法,让不同方法代表不同通知类型

package aopanno;

//增强的类
public class UserProxy {


    //做一个前置通知
    public void before(){
        System.out.println("before.....");
    }
}
3.进行通知的配置

1.在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="aopanno"></context:component-scan>
</beans>

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

利用@Component

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

package aopanno;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

//增强的类
@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="java"></context:component-scan>

    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
4.配置不同类型的通知

在增强类,在作为通知的方法上面添加通知类型注解,使用切入点表达式进行配置

在增强类方法前面使用@Before等

package aopanno;

import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

//增强的类
@Component
@Aspect//生成代理对象
public class UserProxy {
    //@Before注解表示作为前置通知
    @Before(value = "execution(* User.add(..))")
    //做一个前置通知
    public void before(){
        System.out.println("before.....");
    }

    //@AfterReturning表示后置通知
    @AfterReturning(value = "execution(* User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning.....");
    }
    //@After注解表示最终通知
    @After(value = "execution(* User.add(..))")
    public void after(){
        System.out.println("after.....");
    }

    //@AfterThrowing表示异常通知
    @AfterThrowing(value = "execution(* User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing.....");
    }

    //@Around表示环绕通知
    @Around(value = "execution(* User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        System.out.println("被增强之前");
        //被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("被增强之后");
    }
}

这里需要注意的是,Aspect是在增强类上方,而@Before等则是在方法上面

且环绕异常要特殊对待

上代码执行结果:

被增强之前
before…
add…
afterReturning…
after…
被增强之后

异常之间的关系

环绕前通知在前置通知之前

环绕后通知在最终通知之后

若增强通知未被执行 则不执行后置通知

3 两大特殊情况

1.相同切入点进行抽取

若很多通知是同一个execution,那么可以用如下代码进行操作

//相同切入点抽取
    @Pointcut(value = "execution(* User.add(..))")
    public void pointdemo(){

    }

    //@Before注解表示作为前置通知
    @Before(value = "pointdemo()")//将execution直接换成pointdemo()
    //做一个前置通知
    public void before(){
        System.out.println("before.....");
    }
2.有多个增强类对同一个方法进行增强 可设置增强类的优先级

利用@Order进行设置,内部数字越小,优先级越高,最小为0

@Component
@Aspect//生成代理对象
@Order(1)//数字越小优先级越高
public class UserProxy {
    
}

1.7AspectJ配置文件

创建增强类和被增强类
package aopxml;

public class Book {
    public void buy(){
        System.out.println("buy.....");
    }
}
package aopxml;

public class BookProxy {

    public void before(){
        System.out.println("before.....");
    }
}
在spring配置文件中创建两个类的对象
    <!--对象创建-->
    <bean id="book" class="aopxml.Book"></bean>
    <bean id="bookProxy" class="aopxml.BookProxy"></bean>
在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">

    <!--对象创建-->
    <bean id="book" class="aopxml.Book"></bean>
    <bean id="bookProxy" class="aopxml.BookProxy"></bean>

    <!--AOP的增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* aopxml.Book.buy())"/>

        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            
            <!--增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>
</beans>

4 完全注解开发

@Configuration
@ComponentScan(basePackages = {"xxx"})//相当于扫描
@EnableAspectJAutoProxy(proxyTargetClass = true)//相当于Aspect的开启
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值