简单谈谈Spring框架【1】

1、Spring定义

1.1 百度摘要

Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。(由Rod Johnson创建的一个开源框架)

1.2 Spring的一些优点

  • 方便解耦,简化开发
  • 核心IOC与DI的思想
  • AOP编程的支持
  • 声明式的事物支持
  • 包容性,能够集成各种优秀的框架
  • 降低JavaEE API的使用难度
  • 方便程序的测试
  • Spring属于低侵入,代码污染极低

1.3 Spring的各个包

Spring的模块图

Spring项目的各模块
附带:【Spring的各个包的作用】
Spring AOP:Spring的面向切面编程,提供AOP(面向切面编程)的实现
Spring Aspects:Spring提供的对AspectJ框架的整合
Spring Beans:Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。
Spring Context:在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。
spring-context-indexer:
Spring Context Support:Spring context的扩展支持,用于MVC方面。
Spring Core:Spring的核心工具包
Spring expression:Spring表达式语言
spring-framework-bom:统一管理jar包版本
Spring Instrument:Spring对服务器的代理接口
Spring Instrument Tomcat:Spring对tomcat连接池的集成
Spring jcl : JCL采用了设计模式中的“适配器模式”,它对外提供统一的接口,然后在适配类中将对日志的操作委托给具体的日志框架,比如Log4J,Java Logging API等
Spring JDBC:对JDBC 的简单封装
Spring JMS:为简化jms api的使用而做的简单封装
Spring Messaging:集成messaging api和消息协议提供支持。
Spring orm:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
Spring oxm:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
Spring test:对JUNIT等测试框架的简单封装
Spring tx:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。
Spring web:包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。
Spring webmvc:包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、 Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类。
Spring webmvc portlet:Spring MVC的增强
Spring websocket:提供 Socket通信, web端的推送功能

2、Spring 入门案例

2.1 几个小案例

2.1.1 包管理

使用maven管理

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>
    <dependencies>
        <!-- 是apache最早提供的日志的门面接口。提供简单的日志实现以及日志解耦功能 -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2.1.2 IOC的入门小例子

IoC(Inversion of Control,控制反转)。
所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
简单来说:初始化一个对象,不再是使用传统的new方式,而是需要的时候,从Spring的容器中取。
  • 接口类
public interface UserService {

   void addUser();

   void updateUser(String code);

   void delUser(String code);

   User findUserAll();

}
  • 实现类
public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("进入了addUser的方法.............");
    }

    @Override
    public void updateUser(String code) {
        System.out.println("进入了updateUser的方法.............");
    }

    @Override
    public void delUser(String code) {
        System.out.println("进入了delUser的方法.............");
    }

    @Override
    public User findUserAll() {
        System.out.println("进入了findUserAll的方法.............");
        User user = null;
        return user;
    }
}
  • 配置文件
<?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">
    <!-- 配置service
        <bean> 配置需要创建的对象
            id :用于之后从spring容器获得实例时使用的  【组件扫描的情况:默认的id号或者bean的name是类名的首字母小写。】
            class :需要创建实例的全限定类名
    -->
    <bean id="userService" class="com.mall.spring.service.impl.UserServiceImpl"></bean>
</beans>

测试类

public class UserTest {
    /**
     * 测试通过Spring的容器获取bean
     */
    @Test
    public void test() {
        //获取Spring的容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
        //获得bean .不是传统的需要new 出来,只需要通过Spring容器中取
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.addUser();
    }
}

2.1.3 DI 的入门小例子

  • Dao 接口类
public interface UserDao {

    int saveUser(User user);
    int updateUser(String code);
    int delUser(String code);
    User findUser();
}

  • Dao 实现类
public class UserDaoImpl implements UserDao {

    @Override
    public int saveUser(User user) {
        System.out.println("进入了Dao层的saveUser的方法.............");
        return 0;
    }

    @Override
    public int updateUser(String code) {
        System.out.println("进入了Dao层的updateUser的方法.............");
        return 0;
    }

    @Override
    public int delUser(String code) {
        System.out.println("进入了Dao层的delUser的方法.............");
        return 0;
    }

    @Override
    public User findUser() {
        System.out.println("进入了Dao层的findUser的方法.............");
        return null;
    }
}
  • Service接口类

使用IOC例子中的接口

  • Service接口类实现类
public class UserServiceImpl implements UserService {
    /**
     * 注入的对象
     */
    private UserDao userDao;

    /**
     * 注入对象,需要使用到setXXX方法
     * @param userDao
     */
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.saveUser(new User());
        System.out.println("进入了addUser的方法.............");
    }

    @Override
    public void updateUser(String code) {
        System.out.println("进入了updateUser的方法.............");
    }

    @Override
    public void delUser(String code) {
        System.out.println("进入了delUser的方法.............");
    }

    @Override
    public User findUserAll() {
        System.out.println("进入了findUserAll的方法.............");
        User user = null;
        return user;
    }
}
  • 配置文件
<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="userDaoId" class="com.mall.spring.dao.impl.UserDaoImpl"></bean>
    <!-- 配置service
        <bean> 配置需要创建的对象
            id :用于之后从spring容器获得实例时使用的  【组件扫描的情况:默认的id号或者bean的name是类名的首字母小写。】
            class :需要创建实例的全限定类名
    -->
    <bean id="userService" class="com.mall.spring.service.impl.UserServiceImpl">
        <!--使用property进行对象注入
        name :bean的属性名
        ref : 指向具体的实现对象引用
        -->
        <property name="userDao" ref="userDaoId"></property>
    </bean>
</beans>
  • 测试例子
public class UserTest {
    /**
     * 测试通过Spring的容器获取bean
     */
    @Test
    public void test() {
        //获取Spring的容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
        //获得bean .不是传统的需要new 出来,只需要通过Spring容器中取
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.addUser();
    }
}
  • 结果
    运行结果

2.1.4 依赖注入装配Bean 属性

  • 依赖注入方式:构造器注入和setter注入
  • 装配方式(创建应用对象之间协作关系的行为称为装配):手动装配与自动装配
2.1.4.1 基于bean的注入
  • bean对象 :User
public class User {

    public int age;

    String code;

    public String name;

    public User() {
        
    }

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

    public int getAge() {
        return age;
    }

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

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

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

public class Person {

    private User user;

    private String unicode ;

    public Person() {
    }

    public Person(User user, String unicode) {
        this.user = user;
        this.unicode = unicode;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getUnicode() {
        return unicode;
    }

    public void setUnicode(String unicode) {
        this.unicode = unicode;
    }

    @Override
    public String toString() {
        return "Person{" +
                "user=【" + user.getCode() + "," + user.getAge() + "," + user.getName() +
                "】, unicode='" + unicode + '\'' +
                '}';
    }
}

spring的xml配置文件

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

    <bean id="userDaoId" class="com.mall.spring.dao.impl.UserDaoImpl"></bean>
    <!-- 配置service
        <bean> 配置需要创建的对象
            id :用于之后从spring容器获得实例时使用的  【组件扫描的情况:默认的id号或者bean的name是类名的首字母小写。】
            class :需要创建实例的全限定类名
    -->
    <bean id="userService" class="com.mall.spring.service.impl.UserServiceImpl">
        <!--使用property进行对象注入
        name :bean的属性名
        ref : 指向具体的实现对象引用
        -->
        <property name="userDao" ref="userDaoId"></property>
    </bean>

    <!--基于构造器方法注入
        <constructor-arg> 用于配置构造方法一个参数argument
            name :参数的名称
            value:设置普通数据

            ref:引用数据,一般是另一个bean id值
            index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
            type :确定参数类型
    -->
    <bean id="user" class="com.mall.spring.bean.User">
        <!--方式1-->
       <!-- <constructor-arg name="age" value="11" />
        <constructor-arg name="code" value="00001" />
        <constructor-arg name="name" value="张三" />-->

        <!--方式2-->
        <constructor-arg index="0" type="int" value="12"></constructor-arg>
        <constructor-arg index="1" type="java.lang.String" value="00001"></constructor-arg>
        <constructor-arg index="2" type="java.lang.String" value="张三"></constructor-arg>
    </bean>

    <!--基于setter方法
        * 普通数据
            <property name="" value="值">
            等效
            <property name="">
                <value>值
            等效
            <property p:属性=值 />
        * 引用数据
            <property name="" ref="另一个bean">
            等效
            <property name="">
                <ref bean="另一个bean"/>
    -->
    <bean id="userOther" class="com.mall.spring.bean.User" p:name="李四">
        <property name="age" value="13"></property>
        <property name="code">
            <value>00002</value>
        </property>
    </bean>
    <bean id="person" class="com.mall.spring.bean.Person" p:unicode="00000001" >
        <property name="user" ref="userOther"></property>
    </bean>
</beans>
  • 测试类
  @Test
    public void testBean() {
        User user = (User) applicationContext.getBean("user");
        System.out.println("user = " + user);
        User userOther = (User) applicationContext.getBean("userOther");
        System.out.println("userOther = " + userOther);
        Person person = (Person) applicationContext.getBean("person");
        System.out.println("person = " + person);
    }

结果:
测试类

2.1.4.2 基于集合的注入
  • 定义bean
public class Person {

    private User user;

    private String unicode ;

    private String[] arrData ;

    private List list;

    private Set set;

    private Map map;

    public Set getSet() {
        return set;
    }

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

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public List getList() {
        return list;
    }

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

    public String[] getArrData() {
        return arrData;
    }

    public void setArrData(String[] arrData) {
        this.arrData = arrData;
    }

    public Person() {
    }

    public Person(User user, String unicode) {
        this.user = user;
        this.unicode = unicode;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getUnicode() {
        return unicode;
    }

    public void setUnicode(String unicode) {
        this.unicode = unicode;
    }

    @Override
    public String toString() {
        return "Person{" +
                "user=【" + user.getCode() + "," + user.getAge() + "," + user.getName() +
                "】, unicode='" + unicode + '\'' +
                '}';
    }
}
  • 配置文件
 <bean id="person" class="com.mall.spring.bean.Person" p:unicode="00000001" >
        <property name="user" ref="userOther"></property>
        <!--数组的注入-->
        <property name="arrData">
            <array>
                <value>Dene</value>
                <value>Denr</value>
                <value>Dent</value>
                <value>Deny</value>
                <value>Denu</value>
                <value>Deno</value>
            </array>
        </property>
        <!--List集合的注入-->
        <property name="list">
            <list>
                <value>12</value>
                <value>你好</value>
                <value>是的</value>
                <value>我不是</value>
                <value>你就是</value>
            </list>
        </property>
        <!--Set 集合的注入-->
        <property name="set">
            <set>
                <value>121</value>
                <value>你好1</value>
                <value>是的1</value>
                <value>我不是1</value>
                <value>你就是1</value>
            </set>
        </property>
        <!-- Map集合 -->
        <property name="map">
            <map>
                <entry key="name1" value="Lucy"></entry>
                <entry key="name2" value="Jack"></entry>
                <entry>
                    <key><value>name3</value></key>
                    <value>李白</value>
                </entry>
            </map>
        </property>
    </bean>
  • 测试类
@Test
    public void testBean() {
        User user = (User) applicationContext.getBean("user");
        System.out.println("user = " + user);
        User userOther = (User) applicationContext.getBean("userOther");
        System.out.println("userOther = " + userOther);
        Person person = (Person) applicationContext.getBean("person");
        System.out.println("person = " + person);
        System.out.println("person 中的数组 = " + Arrays.toString(person.getArrData()));
        System.out.println("person 中的数组 = " + Arrays.toString(person.getArrData()));
        System.out.println("person 中的List数组 = " + person.getList());
        System.out.println("person 中的Map = " + person.getMap());
    }

测试结果
测试结果
结论:
上面所提到的都是手动装配的方式。当一个对象的属性是另一个对象时,实例化时,需要为这个对象属性进行实例化,这就是装配。如果一个对象只通过接口来表明依赖关系,那么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行切换。但是这样会存在一个问题,在传统的依赖注入配置中,我们必须要明确要给属性装配哪一个bean的引用,一旦bean很多,就不好维护了(**配置文件就会很臃肿 **)。基于这种场景,spring使用注解来进行自动装配,解决这个问题。自动装配就是开发人员不必知道具体要装配哪个bean的引用,这个识别的工作会由spring来完成。与自动装配配合的还有“自动检测”,这 个动作会自动识别哪些类需要被配置成bean,进而来进行装配。这样我们就明白了,自动装配是为了将依赖注入“自动化”的一个简化配置的操作。

2.1.5 装配方式

2.1.5.1 装配分四种:byName, byType, constructor, autodetect。 【可以使用autowire进行配置,不配置,默认使用byName】

比如:
配置文件:

<bean id="userDao" class="com.mall.spring.dao.impl.UserDaoImpl"></bean>
<bean id="userDaoII" class="com.mall.spring.dao.impl.UserDaoImpl"></bean>
<!--使用 property 进行装配-->
<bean id="userService" class="com.mall.spring.service.impl.UserServiceImpl" >
        <property name="userDao" ref="userDaoll"></property>
    </bean>
  • byName:根据属性名自动装配。此选项将检查容器并根据名字查找 ,与属性完全一致的bean,并将其与属性自动装配。
    例子:<bean id="userService" class="com.mall.spring.service.impl.UserServiceImpl" autowire="byName" />

  • byType 如果容器中存在一个与指定属性类型相同的bean,那么将与 该属性自动装配;如果存在多个该类型bean,那么抛出异常, 并指出不能使用byType方式进行自动装配;如果没有找 到相匹配的bean,则什么事都不发生,也可以通过设置 。
    例子:<bean id="userService" class="com.mall.spring.service.impl.UserServiceImpl" autowire="byType">

  • constructor 就是通过构造器来将类型与参数相同的bean进行装配。

  • autodetect 是constructor与byType的组合,会先进行constructor,如果不成功,再进行byType。

2.1.5.2 注解开启与一些自动装配的注解
  • 开启注解 : <context:annotation-config />
  • 扫描注解包路径: <context:component-scan base-package="com.mall.spring" />
2.1.5.2.1 常用的自动装配注解有以下几种:@Autowired,@Resource,@Inject,@Qualifier,@Named
  • @Autowired 使用
    解释:@Autowired注解是byType类型的,这个注解可以用在属性上面,setter方面上面以及构造器上面。使用这个注解时,就不需要在类中为属性添加setter方法了。但是这个属性是强制性的,也就是说必须得装配上,如果没有找到合适的bean能够装配上,就会抛出异常。
    这时可以使用required=false来允许可以不被装配上,默认值为true。
    当required=true时,@Autowired要求必须装配,但是在没有bean能装配上时,就会抛出异常:NoSuchBeanDefinitionException,如果required=false时,则不会抛出异常。
  • @Qualifier注解
    解释:@Qualifier注解使用byName进行装配,这样可以在多个类型一样的bean中,明确使用哪一个名字的bean来进行装配。@Qualifier注解起到了缩小自动装配候选bean的范围的作用,@Qualifier不能单独使用。
    代码展示:
	@Autowired
    @Qualifier(value = "animal")
    private Animal animal;
  • @Resource 注解
    解释:@Resource如有指定的name属性,先按该属性进行byName方式查找装配;其次再进行默认的byName方式进行装配;如果以上都不成功,则按byType的方式自动装配。都不成功,则报异常。(注解也是java ee的)
    如代码:
    @Resource(name = "person")
    private Person person;
    @Resource
    private User user;
  • @Inject注解
    解释:与@Autowired注解作用一样,也是byType类型,而且是java ee提供的,完全可以代替@Autowired注解,但是@Inject必须是强制装配的,没有required属性,也就是不能为null,如果不存在匹配的bean,会抛出异常。
    @Inject也有一个组合的注解,就是@Named注解,与@Qualifier作用一样,也是byName,但是不是spring的,是java ee标准的。这样就出现了两套自动装配的注解组合,@Autowired与@Qualifier是spring提供的,@Inject与@Named是java ee的
2.1.5.2.2 构造器注解:@Controller,@Components,@Service,@Repository和使用@Component标注的自定义注解
	作用:生成的bean的ID默认为类的非限定名,也就是把类的名字的首字母换成小写。可以在这些注解的值中写名bean id的值,比如:@Component(value = "animal")。

几个注解的简单说明:
@Controller注解 只能用控制器类上
@Service注解 只能用在业务类上
@Repository注解 只能用在dao类上
@Component注解 无法按照上面三个注解分类,就用此注解

3、Spring AOP 切面

3.1 概念

3.1.1定义:

定义:
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

3.1.2 基本概念图

概念图

3.1.3 通知类型介绍

介绍
(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名
来访问目标方法中所抛出的异常对象
(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint。

3.2 案例

3.2.1 增加包

使用spring的包:
<!-- spring-aop 依赖 start -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!--处理事务和AOP所需的包 切面-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- spring-aop 依赖 end -->

或许:

 <!-- spring-aop 依赖 start -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- aspectjweaver 处理事务和AOP所需的包  -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
         aopalliance Spring AOP 的接口支持 三个主要业务实体:Advice 、Interceptor、Joinpoint
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- spring-aop 依赖 end -->

3.2.2 基于XML的切面小案例

  • 切入类:
public class TimeHandler {
    public void printTime() {
        System.out.println("当前时间是:" + System.currentTimeMillis());
    }
}
  • 接口类:前面例子的接口类 【interface UserService】
  • 实现类: 前面例子的类 【class UserServiceImpl implements UserService】
  • 配置文件:
<aop:config>
        <aop:aspect id = "time" ref="timeHandler">
            <!--切入Service的所有方法-->
            <aop:pointcut id="timeMethod" expression="execution(* com.mall.spring.service.UserService.*(..))" />
            <!--切入Service的以add开头的方法-->
           <!-- <aop:pointcut id="timeMethod" expression="execution(* com.mall.spring.service.UserService.add*(..))" />-->
            <aop:before method="printTime" pointcut-ref="timeMethod" />
            <aop:after method="printTime" pointcut-ref="timeMethod" />
        </aop:aspect>
    </aop:config>
  • 测试类
 @Test
    public void test() {
        //获得bean .不是传统的需要new 出来,只需要通过Spring容器中取
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.addUser();
        System.out.println("------------------------------------------------------------------");
        userService.updateUser("name");
    }
  • 运行结果:
    结果

3.2.3 基于XML的切面小案例增加横切点,关键字 order 使用

order属性的数字就是横切关注点的顺序

  • 新增日志模拟类:
public class LogHamdler {
    public void logBefore() {
        System.out.println("日志打印前.....before.....");
    }
    public void logAfter() {
        System.out.println("日志打印后.....after.....");
    }
}
  • xml配置
<aop:config>
        <aop:aspect id = "time" ref="timeHandler" order="1">
            <!--切入Service的所有方法-->
            <aop:pointcut id="timeMethod" expression="execution(* com.mall.spring.service.UserService.*(..))" />
            <!--切入Service的以add开头的方法-->
           <!-- <aop:pointcut id="timeMethod" expression="execution(* com.mall.spring.service.UserService.add*(..))" />-->
            <aop:before method="printTime" pointcut-ref="timeMethod" />
            <aop:after method="printTime" pointcut-ref="timeMethod" />
        </aop:aspect>
        <aop:aspect id = "log" ref="logHandler" order="2">
            <aop:pointcut id="logMethod" expression="execution(* com.mall.spring.service.UserService.*(..))" />
            <aop:before method="logBefore" pointcut-ref="logMethod" />
            <aop:after method="logAfter" pointcut-ref="logMethod" />
        </aop:aspect>
    </aop:config>
  • 测试类运行后结果得到
    测试结果

3.2.4 基于注解方式小案例

  • 配置文件
<!--配置自动匹配 aspectJ 注解的 Java 类生成代理对象 -->
<aop:aspectj-autoproxy />
  • 接口类:
public interface PersonService {

    Person addPerson(Person person);

    void delPerson(String code);
}
  • 接口实现类
@Service("personService")
public class PersonServiceImpl implements PersonService {

    @Resource(name = "person")
    private Person person;
    @Resource
    private User user;

    @Override
    public Person addPerson(Person person) {
        System.out.println("进入了PersonServiceImpl类的addPerson()...............");
        return person;
    }

    @Override
    public void delPerson(String code) {
        int i = 10;
        int count = i / 0 ;
        System.out.println("进入了PersonServiceImpl类的delPerson()...............");
    }
}
  • 切面类 一:
package com.mall.spring.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
 * @author 超
 * Create by fengc on  2018/12/2 22:54
 */
@Order(2)
@Aspect
@Component
public class LoggingAspect {

    /**
     * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.
     * 使用 @Pointcut 来声明切入点表达式.
     * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
     */
    @Pointcut("execution(* com.mall.spring.service.PersonService.*(..))")
    public void declareJointPointExpression(){}

    /**
     * 在 com.mall.spring.service.PersonService 接口的每一个实现类的每一个方法开始之前执行一段代码
     */
    @Before("declareJointPointExpression()")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object [] args = joinPoint.getArgs();
        Object object = joinPoint.getTarget();
        System.out.println("The object = " +object+ ",The method = " + methodName + ", begins with = " + Arrays.asList(args) );
    }

    /**
     * 在方法执行之后执行的代码. 无论该方法是否出现异常
     */
    @After("declareJointPointExpression()")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends");
    }

    /**
     * 在方法法正常结束受执行的代码
     * 返回通知是可以访问到方法的返回值的! result
     */
    @AfterReturning(value = "declareJointPointExpression()",returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends with " + result);
    }

    /**
     * 在目标方法出现异常时会执行的代码.
     * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
     */
    @AfterThrowing(value="declareJointPointExpression()",throwing="e")
    public void afterThrowing(JoinPoint joinPoint, Exception e){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " occurs excetion:" + e);
    }
    /**
     * 环绕通知需要携带 ProceedingJoinPoint 类型的参数.
     * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.
     * 且环绕通知必须有返回值, 返回值即为目标方法的返回值
     */
   /* @Around("execution(* com.mall.spring.service.PersonService.*(..))")
    public Object aroundMethod(ProceedingJoinPoint pjd){

        Object result = null;
        String methodName = pjd.getSignature().getName();

        try {
            //前置通知
            System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
            //执行目标方法
            result = pjd.proceed();
            //返回通知
            System.out.println("The method " + methodName + " ends with " + result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("The method " + methodName + " occurs exception:" + e);
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("The method " + methodName + " ends");
        return result;
    }*/
}

  • 切面类二 【为了测试 order关键字 order越小,横切关注点的顺序越先】
@Order(1)
@Aspect
@Component
public class VlidationAspect {

    @Before("com.mall.spring.config.LoggingAspect.declareJointPointExpression()")
    public void validateArgs(JoinPoint joinPoint) {
        System.out.println("-------validateArgs:【Arrays.asList(joinPoint.getArgs())】:" + Arrays.asList(joinPoint.getArgs()));
    }
}

测试类:

package com.mall.spring.service;

import com.mall.spring.bean.Person;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 超
 * Create by fengc on  2018/12/2 23:06
 */
public class PersonTest {

    //获取Spring的容器
    ApplicationContext applicationContext = null;

    @Before
    public void getApplicationContextInstance() {
        applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
    }

    @Test
    public void test() {
        PersonService personService = (PersonService) applicationContext.getBean("personService");
        personService.addPerson(new Person());
        System.out.println("---------------------------------------------------------------------------");
        personService.delPerson("21321");
    }
}

运行结果:
运行结果

总结论
上面总结了Spring的一些基本用法,当做笔记。
总的来说,Spring是一个十分优秀的框架。它颠覆了我们对编程的一些传统观念。
上面主要让大家了解了Spring的主要核心分别是:Spring的IOC(控制反转)和DI(依赖注入),
Spring的AOP 切面的简单效果。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值