Spring 简易入门指南

Spring 学习笔记

一、简介

Spring框架是一个开放源代码的J2EE应用程序框架,由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson/1423612)发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于JEE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。

  • Spring框架主要由七部分组成,分别是 :Spring CoreSpring AOPSpring ORMSpring DAOSpring ContextSpring WebSpring Web MVC

二、IOC理论

1.UserDao接口
public interface UserDao {
    public void getUser();
}
2.UserDaoImpl实现类
public class UserDaoImpl implements UserDao{
    public void getUser() {
        System.out.println("默认获取用户数据!");
    }
}
public class UserDaoSQLImpl implements UserDao{
    public void getUser() {
        System.out.println("SQL获取用户数据!");
    }
}
3.UserService业务接口类
public interface UserService {
    public void getUser();
}
4.UserServiceImpl业务实现类
public class UserServiceImpl implements UserService{
    private UserDao userDao;

    //便于用户注入 DI
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void getUser() {
        userDao.getUser();
    }
}
5.用户调用模拟
public class Test {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        //需要什么,就注入什么
        ((UserServiceImpl) userService).setUserDao(new UserDaoSQLImpl());
        userService.getUser();
    }
}
6.IOC本质
  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection)。

三、IOC容器(xml)

  • IOC Container:Spring用于依赖注入(dependency injection)的容器,其在运行时生成实例对象,

1.创建核心配置文件


  • UserDao实现类
public class UserDao{

    public void getUser() {
        System.out.println("默认获取用户数据!");
    }
}
  • UserService实现类
public class UserService{
    private UserDao userDao;
    
    //便于用户注入 DI
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void getUser() {
        userDao.getUser();
    }
}
  • 在Spring IOC容器中,每一个对象被称为Bean,而我们需要为IOC容器创建配置文件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"
       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">

    <bean id="userDao" class="com.gu_ppy.Dao.UserDao"></bean>

    <bean id="userService" class="com.gu_ppy.service.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>

2.IOC容器使用

  • 在创建配置文件Beans.xml后,且相应的class创建好后,就可以使用我们IOC容器
  • IOC容器创建:
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
  • 测试代码:
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        //获取业务对象,提交业务
        UserServiceImpl bean = context.getBean("userService");
        System.out.println(bean.getUser());//getUser()方法在前面已给出
    }
}

3.Bean实例化对象

  • 在之前的例子中,Beans.xml是使用无参构造器实例化对象,未指明,默认使用无参构造。
<!--    使用默认无参构造器
    Property标签是通过set方法注入     
-->
<bean id="user1" class="com.gu_ppy.pojo.User">
    <property name="id" value="0001"></property>
    <property name="name" value="小明"></property>
    <property name="sex" value=""></property>
</bean>
  • 有参构造方法实例对象:
<!--    使用多参构造器
    type :根据参数类型自动匹配参数
    index:根据参数序号匹配参数
    value:参数实例化传入的值
-->
<bean id="user2" class="com.gu_ppy.pojo.User">
    <constructor-arg type="java.lang.String" index="0" value="002"></constructor-arg>
    <constructor-arg type="java.lang.String" index="1" value="小红"></constructor-arg>
    <constructor-arg type="java.lang.String" index="2" value=""></constructor-arg>
</bean>

创建Bean的三种方式:

<!--    方法一:自给自足,IOC容器创建并赋值-->
<bean id="userServiceImpl2" class="com.gu_ppy.service.UserServiceImpl">
    <property name="userDao" ref="user2"></property>
</bean>
<!--    方法二:通过工厂对象方法创建-->
<bean id="UserDaoFactory" class="com.gu_ppy.factory.UserDaoFactory"/>
<bean factory-bean="UserDaoFactory1" factory-method="getUserDao" id="userDao"/>
<!--    方法三:通过工厂静态方法创建-->
<bean id="UserDaoFactory2" class="com.gu_ppy.factory.UserDaoFactory" factory-method="getUserDao"/>

4.配置

  • 本篇详解Beans.xml的一些配置。

    <!--    用户对象
        类型  变量名 = new 构造方法()
        User user = new User()
        id:Bean的唯一标识符,相当于对象名。
        class:Bean对象对应的全限定名,包名+类名
        property:参数赋值,其实质是set方法注入
        name:相当于别名,而且还可以取多个别名
    -->
    <bean id="user1" class="com.gu_ppy.pojo.User" name = "name1,name2">
        <property name="name" value="小明"></property>
    </bean>
    
4.1 别名
  • 别名标签
<!--使用别名,userService等同于service-->
<alias name="userService" alias="service"></alias>
4.2 import标签
  • 在企业开发中,每个人创建的Beans.xml可能不同,但是我们可以使用import标签将Bean进行统一。
<!-- 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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- More Bean On Here -->
    <import resource="Beans1.xml"></import>
    <import resource="Beans2.xml"></import>
    <import >........</import>
</beans>
<!-- Beans2.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">
     <!-- More Bean On Here -->
   <Bean>......</Bean>
</beans>

Bean3.xml…

4.3 CompoentScan

将一个或多个包下的组件添加到IOC容器中,xml配置方法如下:

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

5.依赖注入

5.1 构造器注入
  • 上诉已描述,详情请参阅上诉的[3.Bean实例化对象](# 3.Bean实例化对象)板块。
5.2 set方式注入
  • set方式注入是通过Property标签进行注入操作,上述已经提到过,参阅简单例子请到[3.Bean实例化对象](# 3.Bean实例化对象)板块。
  • 集合的注入,, , , and (props:java.util.Properties的注入)
<bean id="complexObject" class="example.ComplexObject">
    <!-- (java.util.Properties)注入-->
    <property name="adminEmails">
        <props>
            <prop key="administrator">administrator@example.org</prop>
            <prop key="support">support@example.org</prop>
            <prop key="development">development@example.org</prop>
        </props>
    </property>
    <!-- 数组注入 -->
     <property name="Books">
       <array>
       		<value>book1</value>
            <value>book2</value>
            <value>book3</value>
       </array>
    </property>
    <!-- (java.util.List)-->
    <property name="someList">
        <list>
            <value>a list element followed by a reference</value>
            <ref bean="myDataSource" />
    		<!-- ref标签代表配置文件中已声明的其它实例对象 -->
        </list>
    </property>
    <!-- (java.util.Map) -->
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>
    <!-- (java.util.Set) -->
    <property name="someSet">
        <set>
            <value>just some string</value>
            <ref bean="myDataSource" />
        </set>
    </property>
</bean>
  • Null及""的注入,例子如下:
<!--空对象的注入-->
<property name="map">
    <null/>
</property>
<!--""空字符串的注入-->
<property name="address" value = ""></property>
5.3 扩展方式注入
  • 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">
    
	<bean id="woman" class="com.gu_ppy.pojo.People">
        <property name="name" value="小艺"/>
        <property name="sex" value=""/>
    </bean>
    
    <bean id="woman1" class="com.gu_ppy.pojo.People" p:name="小艺" p:sex=""/>
</beans>
  • c命名空间替代标签,使用的简单例子如下
<?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: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="man" class="com.gu_ppy.pojo.People">
        <constructor-arg name="name" value="小明"/>
        <constructor-arg name="sex" value=""/>
    </bean>

    <bean id="man1" class="com.gu_ppy.pojo.People" c:name="小明" p:sex=""/>
</beans>

6.Bean的作用域

  • Spring默认:单例(Singleton),如不是lazy加载,IOC容器初始化时会实例化这个Bean,在后续通过getBean(…)得到的实例对象就为该实例。在Beans.xml中为Bean配置"scop"属性.如下:
 <bean id="user2" class="com.gu_ppy.pojo.User"  scope="prototype"/>
  • 原型(Prototype),在每次通过getBean(…)方法获取实例对象时,IOC容器会重新调用构造器实例化该对象。同样,需要在Bean的"scop"属性配置为prototype,如下:
<bean id="user1" class="com.gu_ppy.pojo.User" scope="singleton" >
  • 为了区别它们之间的关系,设置了如下测试代码。
public static void test1(ApplicationContext context){
        //原型
        System.out.println("------------------singleton Scope------------------");
        User bean1 = (User)context.getBean("user1");
        System.out.println(bean1.hashCode());

        User bean2 = (User)context.getBean("user1");
        System.out.println(bean2.hashCode());

        System.out.println("------------------prototype Scope------------------");
        User bean3 = (User)context.getBean("user2");
        System.out.println(bean3.hashCode());

        User bean4 = (User)context.getBean("user2");
        System.out.println(bean4.hashCode()); 
}
  • 测试结果展示

image-20200428142746718

  • 还有其它的关于web的作用域,这里不细讲,给出一张官方文档的表格作参考,如需查阅更多关于作用域的用法或信息请查看 Spring 1.5 Bean Scopes 小结
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.

7.自定义Bean

7.1 Bean的生命周期
  • 为了能对容器对Bean的创建及销毁进行进行自定义,我们可以在创建及销毁时指定方法进行执行。

方法一:注解方式实现,为你配置的初始化和销毁方法分别加上@PostConstruct@PreDestroy注解。

//Birds.java
@Component
public class Birds {
    private String type;
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    @PostConstruct
    public void initial(){
        System.out.println("Birds Initial");
    }
    @PreDestroy
    public void destruct(){
        System.out.println("Birds destruct");
    }
}
<!--Beans.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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="birds1" class="com.gu_ppy.pojo.Birds" p:type="麻雀" init-method="init"/>-->

    <context:component-scan base-package="com.gu_ppy.pojo" />
</beans>

方法二:实现Spring自带的InitializingBeanDisposableBean接口

public class AnotherExampleBean implements DisposableBean,InitializingBean {
    @Override
    public void afterPropertiesSet() {
        // do some initialization work
    }
    @Override
    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}
7.2 待更新…

8.Bean的自动装配

Bean的装配方式大致有三种:

  • 在xml中显示配置
  • 在Java中显示配置:通过注解与反射,将在后续章节细讲。
  • 隐式的自动装配:autowire
8.1byName自动装配

byName:通过容器中的id名与该对象的set方法后面的名字自动注入。

Beans.xml:

<bean id="cat" class="com.gu_ppy.pojo.Cat"/>
<bean id="dog" class="com.gu_ppy.pojo.Dog"/>

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

实体类

public class Dog {
    public void shot(){
        System.out.println("Wang~ Wang~");
    }
}
public class Cat {
    public void shot(){
        System.out.println("Miao~");
    }
}
public class People {
    private Cat cat;
    private Dog dog;

    public void speak(){
        System.out.println("I am People");
    }

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

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

测试:

public class Test {
    @org.junit.Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        People = context.getBean("people", People.class);

        System.out.println(people);
    }
}

注意:id名称更改后,如set方法后的名称与之不同,会找不到该Bean,会注入为null。

8.2 byType自动装配

byType:(Default)通过查找上下文中Bean的类型,来注入与自己对象属性类型相同的Bean。

Beans.xml:

<bean id="cat1" class="com.gu_ppy.pojo.Cat"/>
<bean id="dog1" class="com.gu_ppy.pojo.Dog"/>

<bean id="people" class="com.gu_ppy.pojo.People" autowire="byName"/><!--运行时会报错!-->
<bean id="people1" class="com.gu_ppy.pojo.People" autowire="byType"/>

自动装配的目的,但是这里有一些限制:

  • 自动装配的对象不能是简单的普通对象,如,String、int等等。
  • 如果使用了构造器注入或者setter注入,那么将覆盖自动装配的依赖关系。
  • 通过byType自动装配,如装配的属性的对象有多个对应的Bean,那么请指定主要Bean,如:primary=“true”,在装配时,它会默认装配属性primary为true的Bean。
8.3 其它装配方案
  • 这里给出官方文档关于自动装配的模式,这里便不细述。
ModeExplanation
no(Default) No autowiring. Bean references must be defined by ref elements. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system.
byNameAutowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master and uses it to set the property.
byTypeLets a property be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens (the property is not set).
constructorAnalogous to byType but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. 与byType类似。
8.4 排除装配
  • 我们在将同一对象的不同Bean进行装配时,我们除了设置主要Bean以外还可以排除Bean,如下:
<bean id="dog" class="com.gu_ppy.pojo.Dog" autowire-candidate="false"/>
<!--其值为false:代表其不加入到自动装配的候选Bean中,此时装配时,就会忽略该Bean
		 true:代表加入到候选Bean中,与上述相反(默认为true)
		default:代表与高级元素<beans/>的属性default-autowire-candidates一样
-->
8.5 @Autowired
  • 用于自动装配属性

  • 可用在:

    • 属性上
    • set方法上
    @Autowired
    @Qualifier("aUthor") //自动根据Bean名字查找Bean
    private Author author;
    
    @Value("飞鸟集") //直接设值
    private String bookName;
    private ISBN isbn;
    @Autowired
    public void setIsbn(ISBN isbn) {
        this.isbn = isbn;
    }
    
  • 装配是先从byType自动装配,如有多个同类型Bean,然后再通过byName名字查找装配。

  • 可加入@Qualifier(value="xxx")来自动根据Bean名字查找Bean。

额外内容:
@Nullable:说明这个字段可以为null
@Resource:Java自带的自动装配
  • 可以使用Java原生的@Resource来进行自动装配,其装配原则与@Autowired相同。

9.Bean的xml配置分类

为了更直观的查看xml配置,可以将配置分类。

9.1 用于创建对象
  • <Bean/>标签
9.2 用于注入数据
  • <property name="" value=""/>
  • <constructor-arg index="" value=""/>
  • autowire属性。详情查阅 [8.Bean自动装配](# 8.Bean的自动装配)
<bean id="people" class="com.gu_ppy.pojo.People" autowire="byType"/>
  • 详情请查阅[3.Bean实例化对象](# 3.Bean实例化对象).
9.3 用于改变作用范围
  • <bean>标签的scop属性,详情请查阅[6.Bean的作用域](# 6.Bean的作用域)。
9.4 与Bean的生命周期相关
  • 使用init-methoddestroy-method.

  • 详情请查阅[7.1 Bean的生命周期](# 7.1 Bean的生命周期)。

四、注解用法

1.用于创建对象的注解

1.1 @Component
  • 用于声明组件的注解
1.2 @Controller
  • 一般用于表现层
1.3 @Service
  • 一般用在业务层
1.4 @Repository
  • 一般用于持久层

2.注入数据的注解

2.1 @Autowired
  • 自动按照类型注入,只要容器中有唯一的一个Bean对象类型和需要注入的变量类型匹配,则注入成功。
  • 如果容器中对于同一类型的Bean有多个,会先查找变量名,匹配多个Bean的name,是否可以查到唯一的Bean,如是则注入成功,否则会注入失败。更多关于自动装配的信息请查阅 [8.Bean的自动装配](# 8.Bean的自动装配)。
  • 如需要根据name属性或id属性查找Bean注入的Bean。则可以添加@Qualifier来注入指定名称的Bean。
@Autowired(required = false) //required属性:是否一定需要注入
@Qualifier("aUthor")		//自动根据Bean名字查找Bean
private Author author;

required:默认为true,为true时,如在容器中未查到合适的Bean对象,则报异常,为false时,未找到匹配的Bean则不进行注入。

注意:使用注解方式初始化Bean实例对象非必要set方法。注解可通过反射赋值。

2.2 @Resource

​ 与@Qualifier相类似,都是通过指定名称来查找IOC容器中的Bean来进行装配属性。但@Qualifier依赖于@Autowired。如需要使用单一的注解实现指定id的Bean进行注入,则可以使用@Resource,需指定name属性。

@Resource(name = "iSBN")
private ISBN isbn;

注意:上诉三个注入注解都不能注入普通数据类型,只能注入Bean引用。

2.3 @Value
  • 作用:用于指定数据的值,可使用Spring中的SpEl表达式,可指定注入普通数据类型。
    • SpEl写法:${表达式},
  • 机制:在创建好对象后,通过反射注入真实的值。
  • 不通过构造器注入和set方法注入,而是通过反射注入。
@Value("飞鸟集")
private String bookName;

3.用于改变作用范围的注解

@Scop

  • 用于改变Bean的作用范围
@Component
@Scope("prototype")
public class Book {
    ........
}
  • 更多的作用域类型,例如,prototype、singleton、session…等,请查阅xml的容器配置:[6.Bean的作用域](# 6.Bean的作用域)。

4.与生命周期相关的注解

@PostConstruct@PreDestroy

  • 在xml容器配置中,已经讲了,请查阅[7.1 Bean的生命周期](# 7.1 Bean的生命周期)。

五、AOP

1.使用注解实现aop

  • 包结构

image-20200511103026610

  • Spring配置类
@Configuration
//@ComponentScan(basePackageClasses = {com.gu_ppy.demo1.service.Shopping.class,com.gu_ppy.demo1.aspectJ.ShoppingAspectJ.class})
@ComponentScan(basePackages = {"com.gu_ppy.demo1"})
@EnableAspectJAutoProxy(proxyTargetClass = true)//true:使用CGlib   false:JDK动态代理
public class AppConfig {

}
  • 业务接口
/**
 * <p>购物接口
 * @author gu-ppy
 * @Package com.gu_ppy.demo1.service
 * @Description: TODO
 * @date 2020/5/8 22:48
 */
public interface Shopping {
    /**
     * <b> 买东西
     * @param price  价格
     * @return java.lang.String  买了何种东西
     */
    String buy(double price);
    /**
     * <b>逛街,只看不买
     * @param 
     * @return java.lang.String  逛街干什么
     */
    String windowShopping();
}
  • 业务实现
**
 * <p>男孩
 * @author gu-ppy
 * @Package com.gu_ppy.demo1.service.impl
 * @Description: TODO
 * @date 2020/5/8 22:54
 */
@Component
public class Boy implements Shopping {
    @Override
    public String buy(double price) {
        System.out.println(String.format("男孩花%s元购买了Nintendo Switch",price));
        return "Nintendo Switch";
    }
    @Override
    public String windowShopping() {return "陪女孩逛街";}
}
/**
 * <p>女孩
 * @author gu-ppy
 * @Package com.gu_ppy.demo1.service.impl
 * @Description: TODO
 * @date 2020/5/8 22:57
 */
@Component
public class Girl implements Shopping {
    @Override
    public String buy(double price) {
        System.out.println(String.format("女孩花%s元购买了一件漂亮的首饰",price));
        return "一件漂亮的首饰-耳环";
    }
    @Override
    public String windowShopping() {return "莫有好看的东东!";}
}
  • 切面类
/**
 * <p>购物-切面
 * @author gu-ppy
 * @Package com.gu_ppy.demo1.aspectJ
 * @Description: TODO
 * @date 2020/5/8 23:04
 */
@Aspect
@Component
public class ShoppingAspectJ {
    /**
    * <b> 切点设置
    * <br/>execution为AspectJ 切点指示器,用于匹配连接点的执行方法。其余类似于args、bean、this....都是起限制作用
    * @param price
    * @return void
    */
    @Pointcut("execution(* com.gu_ppy.demo1.service.Shopping.buy(..)) && args(price)")
    public void gif(double price){ }
    
    /**
     * <b> 前置通知
     * @param 
     * @return void
     */
    @Before(value = "gif(double)")
    public void before(){
        System.out.println("@before:男女孩购买了东西!");
    }
    /**
     * <b> 后置通知
     * @param 
     * @return void
     */
    @After("gif(double)")
    public void after(){
        System.out.println("@After:购买完毕!");
    }

    /**
     * <b> 返回通知
     * @param result
     * @return void
     */
    @AfterReturning(pointcut = "gif(double)",returning = "result")
    public void returnAfter(Object result){
        System.out.println("@AfterReturning:购买了"+result);
    }
    
    /**
     * <b> 环绕通知
     * <br/>必须添加ProceedingJoinPoint类型的参数,并且调用proceed()方法,否则原方法不会被执行。
     * @param pj
     * @return void
     */
    @Around("gif(double)")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("@Around:环绕开始");
        return pj.proceed();
    }
}
  • 测试
@org.junit.Test
public void testAOP1(){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    Shopping boy = (Shopping) context.getBean("boy");
    boy.buy(2200);
    System.out.println("-------------------我是分割线--------------------");
    Shopping girl = (Shopping) context.getBean("girl");
    girl.buy(200);
}
  • 结果

image-20200511103707247

2.使用原生Spring接口实现aop

  • 实现类
public class Log implements MethodBeforeAdvice, AfterReturningAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        log("将要执行"+method.getName()+"方法,参数为:"+args);
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
       log(method.getName()+"方法执行完毕,参数为:"+args+",返回值为:"+returnValue);
    }
    //扩展的功能:简单日志功能
    public void log(String msg){
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss a");
        System.out.println(formatter.format(new Date())+" "+msg);
    }
}
  • 配置文件:须在SpringApplicationContext.xml中配置
<bean id="userServiceImpl" class="com.gu_ppy.demo1.UserServiceImpl"/><!--供获取实例-->
<bean id="log" class="com.gu_ppy.demo2.Log"/>
<aop:config >
    <aop:pointcut id="logpc" expression="execution(* com.gu_ppy.demo1.UserService.*(..))"/>
    <aop:advisor advice-ref="log" pointcut-ref="logpc"/>
</aop:config>
  • 测试
@org.junit.Test
public void testAop01(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    UserService service = (UserService) context.getBean("userServiceImpl");

    service.modifyUser();
    service.addUser(new User("Andy","33","man"));
}
  • 执行结果

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

3.自定义切面类

其和注解实现的切面类相类似,都是自行DIY切面类。只不过一个使用注解一个使用xml配置。

  • 自定义类
/**
 * <p>切面类
 *
 * @author gu-ppy
 * @Package com.gu_ppy.demo2.aspect
 * @Description: TODO
 * @date 2020/5/11 10:11
 */
public class AspectJ {
    public void befores() {
        System.out.println("before");
    }
    public void afters(){
        System.out.println("after");
    }
    public void arounds(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("around");
        pj.proceed();
    }
}
  • 配置文件
<!-- 方式: 自定义切面类实现切面功能   -->
    <aop:config>
		<!--   定义一个切面    -->
        <aop:aspect ref="aspect" >
			<!--   切点声明   -->
            <aop:pointcut id="point" expression="execution(* com.gu_ppy.demo2.service.impl.UserServiceImpl.*(..))"/>
		   <!-- 	通知方法        -->
            <aop:after method="afters" pointcut-ref="point"/>
            <aop:before method="befores" pointcut-ref="point"/>
            <aop:around method="arounds" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

4.选择实现方式

  • 这里中要考虑:cglibJDK动态代理

img

两种方式:注解与配置选择

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)//true:使用CGlib   false:JDK动态代理
public class AppConfig {

}
<!--   proxy-target-class 为false:JDK     为true:cglib -->
    <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" />

oinPoint pj) throws Throwable {
System.out.println(“around”);
pj.proceed();
}
}


- 配置文件

```xml
<!-- 方式: 自定义切面类实现切面功能   -->
    <aop:config>
		<!--   定义一个切面    -->
        <aop:aspect ref="aspect" >
			<!--   切点声明   -->
            <aop:pointcut id="point" expression="execution(* com.gu_ppy.demo2.service.impl.UserServiceImpl.*(..))"/>
		   <!-- 	通知方法        -->
            <aop:after method="afters" pointcut-ref="point"/>
            <aop:before method="befores" pointcut-ref="point"/>
            <aop:around method="arounds" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

4.选择实现方式

  • 这里中要考虑:cglibJDK动态代理

[外链图片转存中…(img-tuH5hAvO-1603700341002)]

两种方式:注解与配置选择

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)//true:使用CGlib   false:JDK动态代理
public class AppConfig {

}
<!--   proxy-target-class 为false:JDK     为true:cglib -->
    <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值