Spring-02-深入Spring(IOC/AOP)

发布于:2022-12-06 ⋅ 阅读:(309) ⋅ 点赞:(0)

目录

一.Spring增强

异常抛出增强

1.添加依赖

2.定义包含增加方法的JavaBean

3.配置切面​编辑

4.出错跳转​编辑

5.测试

6.运行结果:

最终增强

1.添加依赖

2.定义包含增加方法的JavaBean​编辑

3.配置切面

4.测试

5.运行结果 

环绕增强

1.添加依赖

2.定义包含增加方法的JavaBean

3.配置切面

4.测试

5.运行结果

二.扩展构造注入

使用构造注入完成属性赋值 

1.依赖注入范例:Greeting

2.bean注入

3.测试

P命名空间注入

1.添加依赖(同上)

2.依赖注入范例:Greeting(代码同上一样的)

3.P命名空间注入

4.测试

5.运行结果 

三.使用注解实现Spring IOC

示例: 

@使用Autowired注解

修改applicationContext.xml配置文件

四.使用Java标准注解完成装配

示例1使用@Resource注解实现组件装配

示例2默认按名称匹配 

对比@Autowired注解和@Resource注解 

五.使用注解实现Spring AOP

使用注解方式实现对业务方法前后增加日志

AOP实现类

DAO实现类

Service实现类

Spring核心配置文件

测试

运行结果

六.使用注解定义其他类型的增强

1.使用注解来定义异常抛出增强

AOP

DAO

Service

核心配置文件

测试

运行结果

2.使用注解来定义最终增强

AOP

DAO

Service

核心配置文件

测试

运行结果

3.使用注解来定义环绕增强

AOP

DAO

Service

核心配置文件

测试

小结 

七.总结 


一.Spring增强

异常抛出增强

特点

在目标对象方法抛出异常时织入增强处理

可灵活拔插的异常处理方案

语法

<aop:config>
	 <aop:aspect  ref="增强方法所在的Bean">
		<aop:after-throwing method="增强处理方法" pointcut-ref="切入点id"  throwing="e" />
	 </aop:aspect>
</aop:config>

1.添加依赖

<!--支持切入点表达式等等-->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.6</version>
</dependency>

2.定义包含增加方法的JavaBean

代码: 


public class ErrorLogger {
	private static final Logger log = Logger.getLogger(ErrorLogger.class);

	public void afterThrowing(JoinPoint jp, RuntimeException e) {
		log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
	}
}

3.配置切面

代码:

<?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">
	<bean id="dao" class="dao.impl.UserDaoImpl"></bean>
	<bean id="service" class="service.impl.UserServiceImpl">
		<property name="dao" ref="dao"></property>
	</bean>
	<!-- 声明增强方法所在的Bean -->
	<bean id="theLogger" class="aop.ErrorLogger"></bean>
	<!-- 配置切面 -->
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" />
		<!-- 引用包含增强方法的Bean -->
		<aop:aspect ref="theLogger">
			<!-- 将afterThrowing()方法定义为异常抛出增强并引用pointcut切入点 -->
			<!-- 通过throwing属性指定为名为e的参数注入异常实例 -->
			<aop:after-throwing method="afterThrowing"
				pointcut-ref="pointcut" throwing="e" />
		</aop:aspect>
	</aop:config>
</beans>

4.出错跳转

代码:

/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
public class UserDaoImpl implements UserDao {

	@Override
	public void saveUser(User user) {
		// 这里并未实现完整的数据库操作,仅为说明问题
		System.out.println("保存用户信息到数据库");
//		throw new RuntimeException("为测试程序运行效果抛出的异常");
	}
}

5.测试

代码:

public class Test {

	@org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("service");
		
		User user = new User();
		user.setId(1);
		user.setUsername("test");
		user.setPassword("5997");
		user.setEmail("test@xxx.com");

		service.save(user);
	}
}

6.运行结果:

 

最终增强

特点

无论方法正常运行还是抛出异常,都会在目标方法最后织入增强处理,即:该增强都会得到执行

与Java中finally代码块的作用相似,通常用于释放资源

可灵活拔插 

1.添加依赖

2.定义包含增加方法的JavaBean

代码: 

/**
 * 定义包含增强方法的JavaBean
 */
public class AfterLogger {
	private static final Logger log = Logger.getLogger(AfterLogger.class);

	public void afterLogger(JoinPoint jp) {
		log.info(jp.getSignature().getName() + " 方法结束执行。");
	}
}

3.配置切面

代码: 

<?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">
	<bean id="dao" class="dao.impl.UserDaoImpl"></bean>
	<bean id="service" class="service.impl.UserServiceImpl">
		<property name="dao" ref="dao"></property>
	</bean>
	<!-- 声明增强方法所在的Bean -->
	<bean id="theLogger" class="aop.AfterLogger"></bean>
	<!-- 配置切面 -->
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" />
		<!-- 引用包含增强方法的Bean -->
		<aop:aspect ref="theLogger">
			<!-- 将afterLogger()方法定义为最终增强并引用pointcut切入点 -->
			<aop:after method="afterLogger" pointcut-ref="pointcut"/>
		</aop:aspect>
	</aop:config>
</beans>

4.测试

代码: 

package test;

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

import service.UserService;

import entity.User;


public class Test {

	@org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("service");
		
		User user = new User();
		user.setId(1);
		user.setUsername("test");
		user.setPassword("scs大帅比");
		user.setEmail("5997@qq.com");

		service.save(user);
	}
}

5.运行结果 

环绕增强

特点

目标方法前后都可织入增强处理

可获取或修改目标方法的参数、返回值

可对目标方法进行异常处理,甚至可以决定目标方法是否执行

1.添加依赖

2.定义包含增加方法的JavaBean

代码:

package aop;

import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 定义包含增强方法的JavaBean
 */
public class AroundLogger {
	private static final Logger log = Logger.getLogger(AroundLogger.class);

	public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {
		log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
				+ " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
		try {
			Object result = jp.proceed();
			log.info("调用 " + jp.getTarget() + " 的 "
					+ jp.getSignature().getName() + " 方法。方法返回值:" + result);
			return result;
		} catch (Throwable e) {
			log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
			throw e;
		} finally {
            log.info(jp.getSignature().getName() + " 方法结束执行。");
        }

	}
}

3.配置切面

代码: 

<?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-3.2.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
	<bean id="dao" class="dao.impl.UserDaoImpl"></bean>
	<bean id="service" class="service.impl.UserServiceImpl">
		<property name="dao" ref="dao"></property>
	</bean>
	<!-- 声明增强方法所在的Bean -->
	<bean id="theLogger" class="aop.AroundLogger"></bean>
	<!-- 配置切面 -->
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" />
		<!-- 引用包含增强方法的Bean -->
		<aop:aspect ref="theLogger">
			<!-- 将aroundLogger()方法定义为环绕增强并引用pointcut切入点 -->
			<aop:around method="aroundLogger" pointcut-ref="pointcut"/>
		</aop:aspect>
	</aop:config>
</beans>

4.测试

代码: 

package test;

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

import service.UserService;

import entity.User;


public class Test {

	@org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("service");
		
		User user = new User();
		user.setId(1);
		user.setUsername("test");
		user.setPassword("666");
		user.setEmail("5997@scs.com");

		service.save(user);
	}

}

5.运行结果

二.扩展构造注入

问题

除了使用set方法,还有什么方式实现注入?

分析

可以使用带参构造 Spring通过构造方法为属性赋值的一种注入方式

可以在对象初始化时对属性赋值,具有良好的时效性

<bean id="唯一标识" class="类的全路径">

    <constructor-arg name="参数名称" ref="依赖对象" />//配置被注入的Bean名称

</bean> 

编写带参构造方法后,Java虚拟机不再提供默认的无参构造方法,为了保证使用的灵活性,建议自行添加一个无参构造方法

使用构造注入完成属性赋值 

需求说明

控制台输出

路飞: "我是要成为海贼王的男人! "

诸葛亮: "从未见过如此厚颜无耻之人! "

要求

对话双方和内容需使用构造注入实现依赖注入

提示

当多个参数类型都是字符串类型时,可以使用index属性指定参数下标

1.依赖注入范例:Greeting

代码: 

package cn.service;


public class Greeting {
	// 说话的人
	private String person = "Nobody";
	// 说话的内容
	private String words = "nothing";

	/**
	 * 无参构造
	 */
	public Greeting() {
	}

	/**
	 * 注入person和words
	 */
	public Greeting(String person, String words) {
		this.person = person;
		this.words = words;
	}

	/**
	 * 定义说话方法。
	 */
	public void sayGreeting() {
		System.out.println(person + " 说:“" + words + "”");
	}

}

2.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="luFeiSay" class="cn.service.Greeting">
		<constructor-arg index="1">
			<value>我是要成为海贼王的男人!</value>
		</constructor-arg>
		<constructor-arg index="0">
			<value>路飞</value>
		</constructor-arg>
	</bean>
	<bean id="zhuGeLiangSay" class="cn.service.Greeting">
		<constructor-arg index="0">
			<value>诸葛亮</value>
		</constructor-arg>
		<constructor-arg index="1">
			<value>从未见过如此厚颜无耻之人!</value>
		</constructor-arg>
	</bean>
</beans>

3.测试

 代码:

package test;

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

import cn.service.Greeting;

public class Test {

    @org.junit.Test
    public void test() {
        // 通过ClassPathXmlApplicationContext显式地实例化Spring的上下文
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        // 通过Greeting bean的id来获取bean的实例
        Greeting luFeiSay = (Greeting) context.getBean("luFeiSay");
        Greeting zhuGeLiangSay = (Greeting) context.getBean("zhuGeLiangSay");
        // 执行sayGreeting()方法
        luFeiSay.sayGreeting();
        zhuGeLiangSay.sayGreeting();
    }
}

P命名空间注入

使用属性而不是子元素的形式配置Bean的属性

语法:

<bean id="唯一标识" class="类的全路径"     p:"属性1"="注入的值" p:"属性2"="注入的值"  /> <bean id="唯一标识" class="类的全路径"     p:属性-ref="注入的Bean" />

提示:

配置文件中使用p命名空间时,需要先添加p命名空间的声明 xmlns:p="http://www.springframework.org/schema/p"

需求说明

控制台输出

路飞: "我是要成为海贼王的男人! "

诸葛亮: "从未见过如此厚颜无耻之人! "

要求

使用p命名空间改造前面学员操作中的代码

对话双方和内容需使用setter方法实现依赖注入 

1.添加依赖(同上)

2.依赖注入范例:Greeting(代码同上一样的)

package cn.service;


public class Greeting {
	// 说话的人
	private String person = "Nobody";
	// 说话的内容
	private String words = "nothing";

	/**
	 * 无参构造
	 */
	public Greeting() {
	}

	/**
	 * 注入person和words
	 */
	public Greeting(String person, String words) {
		this.person = person;
		this.words = words;
	}

	/**
	 * 定义说话方法。
	 */
	public void sayGreeting() {
		System.out.println(person + " 说:“" + words + "”");
	}

}

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
    http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="luFeiSay" class="cn.service.Greeting" p:person="路飞"
		p:words="我是要成为海贼王的男人!" />
	<bean id="zhuGeLiangSay" class="cn.service.Greeting" p:person="诸葛亮"
		p:words="从未见过如此厚颜无耻之人!" />
</beans>

4.测试

代码: 

package test;

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

import cn.service.Greeting;

public class Test {
    @org.junit.Test
    public void test() {
        // 通过ClassPathXmlApplicationContext显式地实例化Spring的上下文
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        // 通过Greeting bean的id来获取bean的实例
        Greeting luFeiSay = (Greeting) context.getBean("luFeiSay");
        Greeting zhuGeLiangSay = (Greeting) context.getBean("zhuGeLiangSay");
        // 执行sayGreeting()方法
        luFeiSay.sayGreeting();
        zhuGeLiangSay.sayGreeting();
    }
}

5.运行结果 

两种注入方式其实就修改了applicationContext.xml代码

三.使用注解实现Spring IOC

注解方式将Bean的定义信息和Bean实现类结合在一起,Spring提供的注解有

@Component:实现Bean组件的定义

@Repository:用于标注DAO类

@Service:用于标注业务类

@Controller:用于标注控制器类

示例: 

 @Repository("userDao")//与在XML配置文件中编写 <bean id="userDao"                                                                     //class="dao.impl.UserDaoImpl" />等效

public class UserDaoImpl implements UserDao {

    …

}

@使用Autowired注解

 使用@Autowired注解实现Bean的自动装配

默认按类型匹配,可使用@Qualifier指定Bean的名称

@Service("userService")
public class UserServiceImpl implements UserService {
	@Autowired
	@Qualifier("userDao")
	private UserDao dao;//为dao属性注入名为userDao的Bean
	……
}

修改applicationContext.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
	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="service,dao" />
        <!–指定需要被Spring扫描的基准包范围(多个包名之间用逗号隔开)>
</beans>

四.使用Java标准注解完成装配

使用@Resource注解实现组件装配

默认按名称匹配 

示例1使用@Resource注解实现组件装配

@Service("userService")
public class UserServiceImpl implements UserService {
	@Resource
	private UserDao dao;//找名为dao的Bean,并注入给dao属性
	……
}
@Service("userService")
public class UserServiceImpl implements UserService {
	@Resource(name="userDao")
	private UserDao dao;//为dao属性注入名为userDao的Bean
	……
}

示例2默认按名称匹配 

@Service("userService")
public class UserServiceImpl implements UserService {
	@Resource(type = UserDaoImpl.class)//用于显示指定依赖的Bean的具体类型
	private UserDao dao;
	……
}

对比@Autowired注解和@Resource注解 

  1. @Autowired是Spring提供的注解,@Resource是Java提供的
  2. 在不指定任何参数且不配合其他注解时,@Autowired注解会优先按Bean的类型进行装配,@Resource注解则是优先按Bean的名称进行装配

五.使用注解实现Spring AOP

AspectJ

面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译期提供代码的织入

@AspectJ

AspectJ 5新增的功能,使用JDK 5.0注解技术和正规的AspectJ切点表达式语言描述切面

Spring通过集成AspectJ框架实现了以注解的方式定义切面,使得配置文件的代码大大减少

利用轻量级的字节码处理框架asm处理@AspectJ中所描述的方法参数名

提示 

使用@AspectJ,首先要保证所用的JDK是5.0或以上版本

需求说明

使用注解方式实现对业务方法前后增加日志

使用注解定义前置增强和后置增强实现日志功能

@Aspect

@Before

@AfterReturning

编写Spring配置文件,完成切面织入

<aop:aspectj-autoproxy>:启用对于@AspectJ注解的支持 

AOP实现类

代码

package aop;

import java.util.Arrays;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 通过注解实现增强
 */
@Aspect
public class UserServiceLogger {
	private static final Logger log = Logger.getLogger(UserServiceLogger.class);
	
    /*
    @Pointcut("execution(* service.UserService.*(..))")
    public void pointcut() {}
    */

	@Before("execution(* service.UserService.*(..))")
	public void before(JoinPoint jp) {
		log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
				+ " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
	}

	@AfterReturning(pointcut = "execution(* service.UserService.*(..))", returning = "returnValue")
	public void afterReturning(JoinPoint jp, Object returnValue) {
		log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
				+ " 方法。方法返回值:" + returnValue);
	}

}

DAO实现类

 代码

package dao.impl;

import org.springframework.stereotype.Repository;

import dao.UserDao;
import entity.User;

/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
@Repository
public class UserDaoImpl implements UserDao {

	@Override
	public void saveUser(User user) {
		// 这里并未实现完整的数据库操作,仅为说明问题
		System.out.println("保存用户信息到数据库");
	}
}

Service实现类

 代码

package service.impl;

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

import service.UserService;
import dao.UserDao;
import entity.User;

/**
 * 用户业务类,实现对User功能的业务管理
 */
@Service("userService")
public class UserServiceImpl implements UserService {

	// 声明接口类型的引用,和具体实现类解耦合
    @Autowired
	private UserDao dao;

	// dao 属性的setter访问器,会被Spring调用,实现设值注入
	/*
	public void setDao(UserDao dao) {
		this.dao = dao;
	}
	*/

	@Override
	public void save(User user) {
		// 调用用户DAO的方法保存用户信息
		dao.saveUser(user);
	}
}

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-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
	<context:component-scan base-package="service, dao" />
	<bean class="aop.UserServiceLogger"></bean>
	<aop:aspectj-autoproxy />
</beans>

测试

代码 

package test;

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

import service.UserService;

import entity.User;


public class Test {
    @org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("userService");
		
		User user = new User();
		user.setId(1);
		user.setUsername("test");
		user.setPassword("scs");
		user.setEmail("wsay5997@wsay.com");

		service.save(user);
	}

}

运行结果

六.使用注解定义其他类型的增强

1.使用注解来定义异常抛出增强

分析

使用@AfterThrowing注解定义异常抛出增强

AOP

package aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;

/**
 * 通过注解实现异常抛出增强
 */
@Aspect
public class ErrorLogger {
	private static final Logger log = Logger.getLogger(ErrorLogger.class);

	@AfterThrowing(pointcut = "execution(* service.UserService.*(..))", throwing = "e")
	public void afterThrowing(JoinPoint jp, RuntimeException e) {
		log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
	}

}

DAO

package dao.impl;

import org.springframework.stereotype.Repository;

import dao.UserDao;
import entity.User;

/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
@Repository
public class UserDaoImpl implements UserDao {

	@Override
	public void saveUser(User user) {
		// 这里并未实现完整的数据库操作,仅为说明问题
		System.out.println("进入saveUser方法,保存用户信息到数据库");
		throw new RuntimeException("为测试程序运行效果抛出的异常");
	}
}

Service

package service.impl;

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

import service.UserService;

import dao.UserDao;
import entity.User;

/**
 * 用户业务类,实现对User功能的业务管理
 */
@Service("userService")
public class UserServiceImpl implements UserService {

	// 声明接口类型的引用,和具体实现类解耦合
	@Autowired
    private UserDao dao;

	@Override
	public void save(User user) {
		// 调用用户DAO的方法保存用户信息
		dao.saveUser(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"
	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-3.2.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<context:component-scan base-package="service,dao" />
	<bean class="aop.ErrorLogger"></bean>
	<aop:aspectj-autoproxy />
</beans>

测试

package test;

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

import service.UserService;

import entity.User;


public class Test {

	@org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("userService");
		
		User user = new User();
		user.setId(1);
		user.setUsername("test");
		user.setPassword("wsay5997");
		user.setEmail("wsay@5997.com");

		service.save(user);
	}

}

运行结果

2.使用注解来定义最终增强

分析

使用@After注解定义最终增强

AOP

package aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;

/**
 * 通过注解实现最终增强
 */
@Aspect
public class AfterLogger {
	private static final Logger log = Logger.getLogger(AfterLogger.class);

	@After("execution(* service.UserService.*(..))")
	public void afterLogger(JoinPoint jp) {
		log.info(jp.getSignature().getName() + " 方法结束执行。");
	}

}

DAO

package dao.impl;

import org.springframework.stereotype.Repository;

import dao.UserDao;
import entity.User;

/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
@Repository
public class UserDaoImpl implements UserDao {

	@Override
	public void saveUser(User user) {
		// 这里并未实现完整的数据库操作,仅为说明问题
		System.out.println("保存用户信息到数据库");
//		throw new RuntimeException("为测试程序运行效果抛出的异常");
	}
}

Service

package service.impl;

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

import service.UserService;

import dao.UserDao;
import entity.User;

/**
 * 用户业务类,实现对User功能的业务管理
 */
@Service("userService")
public class UserServiceImpl implements UserService {

	// 声明接口类型的引用,和具体实现类解耦合
	@Autowired
    private UserDao dao;

	@Override
	public void save(User user) {
		// 调用用户DAO的方法保存用户信息
		dao.saveUser(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"
	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-3.2.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<context:component-scan base-package="service,dao" />
	<bean class="aop.AfterLogger"></bean>
	<aop:aspectj-autoproxy />
</beans>

测试

package test;

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

import service.UserService;

import entity.User;


public class Test {

	@org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("userService");
		
		User user = new User();
		user.setId(1);
		user.setUsername("wsay1234r");
		user.setPassword("wsay5997");
		user.setEmail("wsay@1234.com");

		service.save(user);
	}

}

运行结果

 

3.使用注解来定义环绕增强

分析

使用@Around注解定义环绕增强

AOP

package aop;

import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;

/**
 * 通过注解实现环绕增强
 */
@Aspect
public class AroundLogger {
	private static final Logger log = Logger.getLogger(AroundLogger.class);

	@Around("execution(* service.UserService.*(..))")
	public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {
		log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
				+ " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
		try {
			Object result = jp.proceed();
			log.info("调用 " + jp.getTarget() + " 的 "
					+ jp.getSignature().getName() + " 方法。方法返回值:" + result);
			return result;
		} catch (Throwable e) {
			log.error(jp.getSignature().getName() + " 方法发生异常:" + e);
			throw e;
		} finally {
		    log.info(jp.getSignature().getName() + " 方法结束执行。");
		}
	}

}

DAO

package dao.impl;

import org.springframework.stereotype.Repository;

import dao.UserDao;
import entity.User;

/**
 * 用户DAO类,实现UserDao接口,负责User类的持久化操作
 */
@Repository
public class UserDaoImpl implements UserDao {

	@java.lang.Override
	public void saveUser(User user) {
		// 这里并未实现完整的数据库操作,仅为说明问题
		System.out.println("保存用户信息到数据库");
	}
}

Service

package service.impl;

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

import service.UserService;

import dao.UserDao;
import entity.User;

/**
 * 用户业务类,实现对User功能的业务管理
 */
@Service("userService")
public class UserServiceImpl implements UserService {

	// 声明接口类型的引用,和具体实现类解耦合
	@Autowired
    private UserDao dao;

	@Override
	public void save(User user) {
		// 调用用户DAO的方法保存用户信息
		dao.saveUser(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"
	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-3.2.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<context:component-scan base-package="service,dao" />
	<bean class="aop.AroundLogger"></bean>
	<aop:aspectj-autoproxy />
</beans>

测试

package test;

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

import service.UserService;

import entity.User;


public class Test {

	@org.junit.Test
	public void test() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("userService");
		
		User user = new User();
		user.setId(1);
		user.setUsername("wsay56789");
		user.setPassword("wsay5dd997");
		user.setEmail("wsay@46464.com");

		service.save(user);
	}

}

小结 

  • Spring在同一个功能上提供了注解和配置文件两种实现方式以供选择
  • 通常情况下,优先选择注解来简化配置工作量
  • 常用的注解

@AfterThrowing

@Before

@AfterReturning

@Around

@After

@Aspect

@Pointcut

七.总结 

以上就是Spring增强,扩展构造注入,使用注解实现IOC,AOP,使用注解定义其他类型的增强

下一篇博文:Spring-03-Spring整合MyBatis

上一篇博文地址:Spring-01-初识Spring

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到