spring 控制反转(IOC)与 面向切面编程 (AOP)示例

spring (由Rod Johnson创建的一个开源框架)

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

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com</groupId>
<artifactId>springDemo</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
</dependencies>
</project>

UserDao 接口类

1
2
3
4
5
6
7
package com.dao;

import com.pojo.User;

public interface UserDao {
User queryUser(String userName);
}

UserService 接口类

1
2
3
4
5
6
7
package com.service;

import com.pojo.User;

public interface UserService {
User queryUser(String userName);
}

ApplicationContextUtil 工具类

1
2
3
4
5
6
7
8
9
10
11
package com.util;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextUtil {
public static ClassPathXmlApplicationContext context;

static {
context = new ClassPathXmlApplicationContext("applicationContextAop.xml");
}
}

XML方式配置

applicationContextAop.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?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"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--setter 设值注入-->
<bean name="peter" class="com.pojo.User">
<property name="name" value="Peter"/>
<property name="info" value="Peter-info"/>
</bean>
<!--构造方法 构造注入-->
<bean name="simon" class="com.pojo.User">
<constructor-arg index="0" value="Simon"/>
<constructor-arg index="1" value="Simon-info"/>
</bean>
<!--setter p命名空间注入-->
<bean name="admin" class="com.pojo.User" p:name="admin" p:info="admin-info"/>

<bean name="userLog" class="com.log.UserLog"/>
<aop:config>
<!--定义切入点 expression 值 必须写到 execution() 里面-->
<aop:pointcut id="point" expression="execution(* com.pojo..*.*(..))"/>
<aop:pointcut id="pointAll" expression="execution(* *.*(..))"/>

<aop:aspect ref="userLog">
<!--method 指定 com.log.UserLog 里面的方法 pointcut-ref 为上面的定义切入点-->
<!--前置增强-->
<aop:before method="before" pointcut-ref="point"/>
<!--后置增强-->
<aop:after-returning method="returning" pointcut-ref="point" returning="result"/>
<!--环绕增强-->
<aop:around method="around" pointcut-ref="point"/>
<!--最终增强-->
<aop:after method="after" pointcut-ref="point"/>
<!--异常抛出增强-->
<aop:after-throwing method="throwing" pointcut-ref="pointAll" throwing="e"/>
</aop:aspect>
</aop:config>

<bean name="userDao" class="com.dao.impl.UserDaoImpl"/>
<bean name="userService" class="com.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<bean name="userServlet" class="com.servlet.UserServlet">
<property name="userService" ref="userService"/>
</bean>
</beans>

UserLog 面向切面编程 (AOP)类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.log;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Arrays;

public class UserLog {
/**
* 前置增强
*/
public void before(JoinPoint joinPoint) {
System.out.println("调用前置增强 " + joinPoint.getTarget() + " 的 " + joinPoint.getSignature().
getName() + " 方法。方法入参: " + Arrays.toString(joinPoint.getArgs()));
}

/**
* 后置增强
*/
public void returning(JoinPoint joinPoint, Object result) {
System.out.println("调用后置增强 " + joinPoint.getTarget() + " 的 " + joinPoint.getSignature().
getName() + " 方法。方法返回值: " + result);
}

/**
* 环绕增强
*/
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("调用环绕增强 " + pjp.getTarget() + " 的 " + pjp.getSignature().
getName() + " 方法。方法入参: " + Arrays.toString(pjp.getArgs()));

// 异常必须抛出,不然异常抛出增强进不去
Object proceed = pjp.proceed();

System.out.println("调用环绕增强 " + pjp.getTarget() + " 的 " + pjp.getSignature().
getName() + " 方法。方法返回值: " + proceed);

return proceed;
}

/**
* 最终增强
*/
public void after(JoinPoint joinPoint) {
System.out.println("调用最终增强 " + joinPoint.getSignature().getName() + " 方法结束执行");
}

/**
* 异常抛出增强
*/
public void throwing(JoinPoint joinPoint, Exception e) {
System.out.println("调用异常抛出增强 " + joinPoint.getSignature().getName() + " 方法发生异常: " + e);
}
}

UserDaoImpl 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.dao.impl;

import com.dao.UserDao;
import com.pojo.User;
import com.util.ApplicationContextUtil;

public class UserDaoImpl implements UserDao {
public User queryUser(String userName) {
User user = ApplicationContextUtil.context.getBean(userName, User.class);
user.print();
return user;
}
}

UserServiceImpl 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.service.impl;

import com.dao.UserDao;
import com.pojo.User;
import com.service.UserService;

public class UserServiceImpl implements UserService {
private UserDao userDao;

public User queryUser(String userName) {
if (userName == null)
throw new RuntimeException("自定义异常触发");
return userDao.queryUser(userName);
}

/**
* 提供设置UserDao的setter方法
*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}

UserServlet 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.servlet;

import com.service.UserService;

public class UserServlet {
private UserService userService;

public void doGet(String userName) {
userService.queryUser(userName);
}

/**
* 提供设置UserService的setter方法
*/
public void setUserService(UserService userService) {
this.userService = userService;
}
}

注解方式配置

applicationContextAop.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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"
xmlns:p="http://www.springframework.org/schema/p"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--setter 设值注入-->
<bean name="peter" class="com.pojo.User">
<property name="name" value="Peter"/>
<property name="info" value="Peter-info"/>
</bean>
<!--构造方法 构造注入-->
<bean name="simon" class="com.pojo.User">
<constructor-arg index="0" value="Simon"/>
<constructor-arg index="1" value="Simon-info"/>
</bean>
<!--setter p命名空间注入-->
<bean name="admin" class="com.pojo.User" p:name="admin" p:info="admin-info"/>


<!--扫描哪个包的注解-->
<context:component-scan base-package="com"/>

<!--面向切面编程 (AOP)使用注解增强处理-->
<aop:aspectj-autoproxy/>
</beans>

UserLog 面向切面编程 (AOP)类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.log;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class UserLog {
/**
* 前置增强
*/
@Before(value = "execution(* com.pojo..*.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("调用前置增强 " + joinPoint.getTarget() + " 的 " + joinPoint.getSignature().
getName() + " 方法。方法入参: " + Arrays.toString(joinPoint.getArgs()));
}

/**
* 后置增强
*/
@AfterReturning(value = "execution(* com.pojo..*.*(..))", returning = "result")
public void returning(JoinPoint joinPoint, Object result) {
System.out.println("调用后置增强 " + joinPoint.getTarget() + " 的 " + joinPoint.getSignature().
getName() + " 方法。方法返回值: " + result);
}

/**
* 环绕增强
*/
@Around(value = "execution(* com.pojo..*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("调用环绕增强 " + pjp.getTarget() + " 的 " + pjp.getSignature().
getName() + " 方法。方法入参: " + Arrays.toString(pjp.getArgs()));

// 异常必须抛出,不然异常抛出增强进不去
Object proceed = pjp.proceed();

System.out.println("调用环绕增强 " + pjp.getTarget() + " 的 " + pjp.getSignature().
getName() + " 方法。方法返回值: " + proceed);

return proceed;
}

/**
* 最终增强
*/
@After(value = "execution(* com.pojo..*.*(..))")
public void after(JoinPoint joinPoint) {
System.out.println("调用最终增强 " + joinPoint.getSignature().getName() + " 方法结束执行");
}

/**
* 异常抛出增强
*/
@AfterThrowing(value = "execution(* *.*(..))", throwing = "e")
public void throwing(JoinPoint joinPoint, Exception e) {
System.out.println("调用异常抛出增强 " + joinPoint.getSignature().getName() + " 方法发生异常: " + e);
}
}

UserDaoImpl 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.dao.impl;


import com.dao.UserDao;
import com.pojo.User;
import com.util.ApplicationContextUtil;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

//@Component("userDao")

/**
* Repository 等同 Component
*/
@Repository("userDao")
public class UserDaoImpl implements UserDao {

public User queryUser(String userName) {
User user = ApplicationContextUtil.context.getBean(userName, User.class);
user.print();
return user;
}

}

UserServiceImpl 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.service.impl;

import com.dao.UserDao;
import com.pojo.User;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

//@Component("userService")

/**
* Service 等同 Component
*/
@Service("userService")
public class UserServiceImpl implements UserService {
// @Autowired
// @Qualifier("userDao")
/**
* Resource 等同 Autowired 与 Qualifier 的结合
*/
@Resource(name = "userDao")
private UserDao userDao;

public User queryUser(String userName) {
if (userName == null)
throw new RuntimeException("自定义异常触发");
return userDao.queryUser(userName);
}

/**
* 提供设置UserDao的setter方法
*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}

UserServlet 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.servlet;

import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

//@Component("userServlet")

/**
* Controller 控制层等同Component
*/
@Controller("userServlet")
public class UserServlet {
// @Autowired
// @Qualifier("userService")
/**
* Resource 不给值会自动匹配去找类型一致的UserService 等同 Autowired 与 Qualifier 的结合
*/
@Resource
private UserService userService;

public void doGet(String userName) {
userService.queryUser(userName);
}

/**
* 提供设置UserService的setter方法
*/
public void setUserService(UserService userService) {
this.userService = userService;
}
}

User 实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.pojo;

public class User {
private String name;
private String info;

public User() {
}

public User(String name, String info) {
this.name = name;
this.info = info;
}

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

public void print() {
System.out.println(toString());
}

public void Runtime() {
throw new RuntimeException("禁止输出");
}

public String getName() {
return name;
}

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

public String getInfo() {
return info;
}

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

main 测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.test;

import com.servlet.UserServlet;
import com.util.ApplicationContextUtil;

public class main {
public static void main(String[] args) {
UserServlet userServlet = ApplicationContextUtil.context.getBean("userServlet", UserServlet.class);
System.out.println("控制反转(IOC)输出测试--------------------------------------------");
userServlet.doGet("simon");
userServlet.doGet("admin");
userServlet.doGet("peter");
System.out.println("面向切面编程(AOP)测试--------------------------------------------");
userServlet.doGet("admin");
System.out.println("面向切面编程(AOP)异常抛出增强测试----------------------------------");
userServlet.doGet(null);
}
}

XML方式配置 控制台输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
控制反转(IOC)输出测试--------------------------------------------
调用前置增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法入参: []
调用环绕增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法入参: []
User{name='Simon', info='Simon-info'}
调用最终增强 print 方法结束执行
调用环绕增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法返回值: null
调用后置增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法返回值: null
调用前置增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
User{name='admin', info='admin-info'}
调用最终增强 print 方法结束执行
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
调用后置增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
调用前置增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法入参: []
调用环绕增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法入参: []
User{name='Peter', info='Peter-info'}
调用最终增强 print 方法结束执行
调用环绕增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法返回值: null
调用后置增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法返回值: null
面向切面编程(AOP)测试--------------------------------------------
调用前置增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
User{name='admin', info='admin-info'}
调用最终增强 print 方法结束执行
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
调用后置增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
面向切面编程(AOP)异常抛出增强测试----------------------------------
调用异常抛出增强 queryUser 方法发生异常: java.lang.RuntimeException: 自定义异常触发
调用异常抛出增强 doGet 方法发生异常: java.lang.RuntimeException: 自定义异常触发

注解方式配置 控制台输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
控制反转(IOC)输出测试--------------------------------------------
调用环绕增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法入参: []
调用前置增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法入参: []
User{name='Simon', info='Simon-info'}
调用环绕增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法返回值: null
调用最终增强 print 方法结束执行
调用后置增强 User{name='Simon', info='Simon-info'} 的 print 方法。方法返回值: null
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
调用前置增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
User{name='admin', info='admin-info'}
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
调用最终增强 print 方法结束执行
调用后置增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
调用环绕增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法入参: []
调用前置增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法入参: []
User{name='Peter', info='Peter-info'}
调用环绕增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法返回值: null
调用最终增强 print 方法结束执行
调用后置增强 User{name='Peter', info='Peter-info'} 的 print 方法。方法返回值: null
面向切面编程(AOP)测试--------------------------------------------
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
调用前置增强 User{name='admin', info='admin-info'} 的 print 方法。方法入参: []
User{name='admin', info='admin-info'}
调用环绕增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
调用最终增强 print 方法结束执行
调用后置增强 User{name='admin', info='admin-info'} 的 print 方法。方法返回值: null
面向切面编程(AOP)异常抛出增强测试----------------------------------
调用异常抛出增强 queryUser 方法发生异常: java.lang.RuntimeException: 自定义异常触发
调用异常抛出增强 doGet 方法发生异常: java.lang.RuntimeException: 自定义异常触发