SSH框架之旅-spring(2)

spring.jpg

1.Spring 中的 bean 管理(注解方式)


1.1 使用注解创建对象

Spring 创建对象可以使用配置 xml 文件的方式,也可以使用注解来创建对象,更加的简单。这就需要另外引入一个 spring-aop 的 jar 包,还要在配置文件中加上相对应的约束。

示例代码如下:

实体类

加上注解,@Component(value="student") 注解就相当于之前用配置 <bean id="student" class="..."/>

创建对象有四个注解,另外三个注解 @controller@Service@Repository 都是 @Component 的衍生注解,它们在功能上是一样的,都是创建对象。从名称上也可以看出注解有划分要标注的类的用途,@Component 用于一般的实体类,@controller 用于 Web 层,@Service 用于 业务逻辑层,@Repository 用于数据持久层。

另外,创建对象是单实例还是多实例也是可以使用注解,只需要在类上加上 @Scope(value="prototype") 就可以创建多实例的对象。

    package cc.wenshixin.entity;
    
    import org.springframework.stereotype.Component;
    
    @Component(value="student")
    public class Student {
        public void study(){
            System.out.println("学习中。。。");
        }
    }

配置文件

在约束配置要加上 xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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: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="cc.wenshixin"></context:component-scan>
</beans>

测试方法

package cc.wenshixin.test;

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

import cc.wenshixin.entity.Student;

public class Test1 {
    
    @Test
    public void test01()
    {
        //1.加载spring的配置文件,根据配置文件来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到通过注解创建的对象
        Student s = (Student) context.getBean("student");
        s.study();
    }
    
}

1.2 使用注解注入属性

创建 service 类和创建 dao 类,在 service 中得到 dao 类的对象。

dao 类

    package cc.wenshixin.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository(value="dao")
    public class Dao {
        public void insert()
        {
            System.out.println("插入数据。。。");
        }
    }

service 类

使用注解方式来注入属性,有两种方式,并且两种方式都不要需要在 dao 中添加 set 方法。

package cc.wenshixin.service;

import javax.annotation.Resource;

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

import cc.wenshixin.dao.Dao;

@Service(value="service")
public class StudentService {
    //第一种方式
    /*@Autowired
    private Dao dao;*/

    //第二种方式
    //name属性值写创建 dao 对象时注解中的 value 值
    @Resource(name="dao")
    private Dao dao;
    
    public void add()
    {
        System.out.println("添加操作。。。");
        dao.insert();
    }
}

测试方法

package cc.wenshixin.test;

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

import cc.wenshixin.entity.Student;
import cc.wenshixin.service.StudentService;

public class Test1 {
    
    @Test
    public void test01()
    {
        //1.加载spring的配置文件,根据配置文件来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到通过注解创建的对象
        StudentService service = (StudentService) context.getBean("service");
        service.add();
    }
}

1.3 配置方式和注解方式的混合使用

在开发中,经常 xml 配置文件方式和注解方式混合使用,创建对象使用配置文件,而属性注入使用注解方式。xml 配置方式结构清晰,注解方式方便属性注入。

Spring 中 bean 管理方式的比较

xml配置

注解配置

bean 定义

<bean id="" class=""/>

@Component,@Respository,@Service,@Controller

bean 名称

通过id或者name指定

@Component("student"),单个value值,value可以省略

bean 注入

<property>或者通过p命名空间

@Autowired 按类型注入,@Resource(name="")

示例代码如下:

dao 类

package cc.wenshixin.dao;

public class TeacherDao {
    public void insert()
    {
        System.out.println("添加老师。。。");
    }
}
package cc.wenshixin.dao;

public class StudentDao {
    public void insert()
    {
        System.out.println("添加学生。。。");
    }
}

service 类

package cc.wenshixin.service;

import javax.annotation.Resource;
import cc.wenshixin.dao.StudentDao;
import cc.wenshixin.dao.TeacherDao;

public class Service {
    @Resource(name="teacherDao")
    private TeacherDao teacherDao;
    @Resource(name="studentDao")
    private StudentDao studentDao;
    
    public void add()
    {
        System.out.println("添加操作。。。");
        teacherDao.insert();
        studentDao.insert();
    }
}

配置文件

<?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">
  <!-- 配置对象 -->
  <bean id="service" class="cc.wenshixin.service.Service"></bean>
  <bean id="teacherDao" class="cc.wenshixin.dao.TeacherDao"></bean>
  <bean id="studentDao" class="cc.wenshixin.dao.StudentDao"></bean>
  
  <!-- 开启注解扫描 -->
  <context:component-scan base-package="cc.wenshixin"></context:component-scan>
</beans>

测试方法

package cc.wenshixin.test;

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

import cc.wenshixin.service.Service;

public class Test1 {
    @Test
    public void test()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Service service = (Service) context.getBean("service");
        service.add();
    }
}

2.Spring 中的 AOP


2.1 AOP 完整概述

AOP,全名 Aspect Oriented Programming,面向切面编程,在 Struts2 的拦截器中已经提到过 AOP,时通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,扩展功能而不修改源代码,如:权限校验、日志记录、性能监控、事务控制。AOP采取横向抽取机制,取代了传统纵向继承体系的重复代码。AOP 解决 OOP(面向对象编程) 中遇到的一些问题,是 OOP 的延续和扩展。

底层的动态代理机制有两种:

    1. 有接口,JDK的动态代理,针对实现接口的类产生代理,生成接口实现类对象。
    1. 没有接口,Cglib的动态代理,应用的是底层的字节码增强技术,生成当前类的子类对象。

2.2 AOP 的底层原理

纵向抽取机制

传统方式.png

横向抽取机制

有接口.png

无接口.png

2.3 AOP 操作的相关术语

  • Joinpoint(连接点):类里面可以被增强的方法,这些方法就称为是连接点。
  • Pointcut(切入点):切入点是指要对连接点进行拦截。在一个类里面可以有很多的方法被增强,比如实际操作中,只是增强了类里面的 add 方法和 update 方法,实际增强的方法就称为是切入点。
  • Advice(通知/增强):通知是指拦截到 Joinpoint 之后要做的事情就是通知,通知又分为前置通知、后置通知、异常通知,最终通知、环绕通知(切面要完成的功能)。要增强的逻辑功能称为是增强,比如扩展日志功能,这个日志功能就成为是通知或者是增强。前置通知:在增强的方法之前执行;后置通知:在增强的方法之后执行;异常通知:方法出现异常时;最终通知:在后置之后执行;环绕通知:在方法之前和之后执行。
  • Aspect(切面):切入点和通知(引介)的结合。把增强应用到具体方法上面的过程称为切面。把增强用到切入点过程。
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。
  • Target(目标对象):代理的目标对象(要增强的类)。
  • Weaving(织入):是把增强应用到目标的过程,也即是把 advice 应用到 target 的过程。
  • Proxy(代理):一个类被 AOP 织入增强后就产生一个结果代理类。

2.4 AOP 的实际操作

在 Spring 中进行 AOP 操作使用 Aspectj 实现的,Aspectj 不是 Spring 的一部分,和 Spring 一起使用 AOP 操作。 使用 Aspectj 实现 AOP 也有两种方式:

  • 1.基于 Aspectj 的xml配置
  • 2.基于 Aspectj 的注解方式

除了上面的 jar 包之外,还需要导入 Aspectj 的相关 jar 包 Aspectjweaver.jar 下载地址aopalliance.jar,这个在 Struts2 的lib中有,spring-aop.jarspring-aspects.jar

2.4.1 配置文件方式

实体类

package cc.wenshixin.entity;

public class Student {
    public void study()
    {
        System.out.println("学习中。。。");
    }
}

增强类

package cc.wenshixin.entity;

import org.aspectj.lang.ProceedingJoinPoint;

public class StrengthStudent {
    public void beforeStudy()
    {
        System.out.println("前置增强。。。");
    }
    
    public void afterStudy()
    {
        System.out.println("后置增强。。。");
    }
    
    //环绕通知
    public void aroundStudy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //方法之前执行
        System.out.println("方法之前。。。");
        //执行被增强的方法
        proceedingJoinPoint.proceed();
        //方法之后执行
        System.out.println("方法之后。。。");
    }
}

配置文件

aspectj配置常用的表达式 execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

  • 1.execution(* cc.wenshixin.entity.Student.add(..))
  • 2.execution(* cc.wenshixin.entity.Student.*(..))
  • 3.execution(* *.*(..))

注意:第一个和后面的路径有一个空格,后面的括号中是两个点,不是三个点*

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  <!-- 1.配置对象 -->
  <bean id="student" class="cc.wenshixin.entity.Student"></bean>
  <bean id="strengthStudent" class="cc.wenshixin.entity.StrengthStudent"></bean>
  <!-- 2.配置 AOP 操作 -->
  <aop:config>
    <!-- 2.1 配置切入点 -->
    <aop:pointcut expression="execution(* cc.wenshixin.entity.Student.*(..))" id="pointCut"/>
    <!-- 2.2 配置切面把增强用到方法上面 -->
    <aop:aspect ref="strengthStudent">
      <aop:before method="beforeStudy" pointcut-ref="pointCut"/>
      <aop:after-returning method="afterStudy" pointcut-ref="pointCut"/>
      <aop:around method="aroundStudy" pointcut-ref="pointCut"/>
    </aop:aspect>
  </aop:config>
</beans>

测试方法

package cc.wenshixin.test;

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

import cc.wenshixin.entity.Student;

public class Test1 {
    @Test
    public void test()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Student s = (Student) context.getBean("student");
        s.study();
    }
}

2.4.2 注解方式

实体类同上

增强类 Aspectj 的 AOP 注解

  • @Aspect:定义切面增强类的注解
  • 通知(增强)类型
    • @Before:前置通知
    • @AfterReturing:后置通知
    • @Around:环绕通知
    • @AfterThrowing:异常抛出通知
package cc.wenshixin.entity;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class StrengthStudent {
    @Before(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void beforeStudy()
    {
        System.out.println("前置增强。。。");
    }
    @After(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void afterStudy()
    {
        System.out.println("后置增强。。。");
    }
    
    //环绕通知
    @Around(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void aroundStudy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //方法之前执行
        System.out.println("方法之前。。。");
        //执行被增强的方法
        proceedingJoinPoint.proceed();
        //方法之后执行
        System.out.println("方法之后。。。");
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  <!-- 1.配置对象 -->
  <bean id="student" class="cc.wenshixin.entity.Student"></bean>
  <bean id="strengthStudent" class="cc.wenshixin.entity.StrengthStudent"></bean>
  <!-- 2.开启AOP操作 -->
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试方法同上

3. 其他概念


3.1 log4j 的介绍

log4j 是一个日志包,通过 log4j 可以看到程序运行过程中更详细的信息,查看日志。使用时需要导入 log4j 的 jar 包,下载位置,并复制 log4j 的配置文件 log4j.properties 到 src 目录。

log4j.properties文件中的内容

log4j.rootLogger 用来设置日志的级别,info可以看到基本信息,debug可以看到更详细的信息。

#
# Log4J Settings for log4j 1.2.x (via jakarta-commons-logging)
#
# The five logging levels used by Log are (in order):
#
#   1. DEBUG (the least serious)
#   2. INFO
#   3. WARN
#   4. ERROR
#   5. FATAL (the most serious)


# Set root logger level to WARN and append to stdout
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%d %5p (%c:%L) - %m%n

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏阿杜的世界

实践基于Redis的分布式锁应用场景实现方式基于Redis的实践参考资料

本文来自社区这周的讨论话题—— 技术专题讨论第四期:漫谈分布式锁,也总结了我对分布式锁的认知和使用经验。

2243
来自专栏weixuqin 的专栏

spring 学习(三):aop 学习

3 aop底层使用动态代理实现 (1)第一种情况,有接口情况,使用动态代理创建接口实现类代理对象 (2)第二种情况,没有接口情况,使用动态代理创建类的子类代...

1092
来自专栏xingoo, 一个梦想做发明家的程序员

基于配置的Spring AOP

前面几篇学习了Spring的依赖注入,这篇开始学习另一个核心功能——面向切面编程AOP。 通过本文,你可以了解到:  1 Spring xml规范 ...

2235
来自专栏Java编程技术

Spring事务切面原理

本节我们来谈谈 <tx:advice/>、<aop:config> 标签如何创建事务切面的。

2102
来自专栏钟绍威的专栏

spring整合hibernate

spring整合hibernate包括三部分:hibernate的配置、hibernate核心对象交给spring管理、事务由AOP控制 好处: 由java代码...

19210
来自专栏Java3y

Spring入门这一篇就够了

前言 前面已经学习了Struts2和Hibernate框架了。接下来学习的是Spring框架…本博文主要是引入Spring框架… Spring介绍 Spring...

2.4K6
来自专栏Java架构沉思录

Spring AOP失效之谜

AOP(Aspect Oriented Programming),即面向切面编程,其是OOP(Object Oriented Programming,面向对象编...

1262
来自专栏用户画像

Spring AOP和IOC

Spring的核心机制是依赖注入(Dependency Inversion),也称为控制反转(IOC)。所谓依赖注入,就是指运行工程中,如果需要调用另一个对象协...

651
来自专栏大数据平台TBDS

Flume-Hbase-Sink针对不同版本flume与HBase的适配研究与经验总结

导语:本文细致而全面地讲解使用flume输出数据到HBase的三种不同 Flume-Hbase-Sink 之间的差异性,以及技术细节。并且透彻而全面地总结了不同...

2K12
来自专栏Java架构沉思录

Spring AOP失效之谜

什么是AOP 1 AOP(Aspect Oriented Programming),即面向切面编程,其是OOP(Object Oriented Program...

4239

扫码关注云+社区

领取腾讯云代金券