Fork me on GitHub

Spring——Ioc和AOP

Spring——Ioc和AOP

这两天学习了Spring框架的主要特性,包括Bean、DI、IoC、AOP、jdbc事务等,写篇博客来做个总结,主要介绍IoC和AOP

Ioc

IoC(Inversion of Control)

​ Ioc(控制反转)也称为DI(依赖注入),它是一个过程,对象仅通过构造函数参数、工厂方法的参数或从工厂方法构造或返回对象实例后在其上设置的属性来定义其依赖项(即与之一起工作的其他对象); 或从工厂方法构造或返回对象实例后在其上设置的属性。然后,容器在创建bean时注入这些依赖项。这个过程基本上是bean本身的逆过程(因此称为控制反转),通过直接构造类或服务定位器模式等机制来控制其依赖项的实例化或位置

代码测试
业务代码

(1)、Person类

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package net.zzqd.spring.pojo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
* @author zzq
* @version 创建时间:2019年5月28日 下午9:04:53
*
*/

public class Person
{
private String name;
private Integer age;
private Car car;

private Object[] cars;//数组类型的注入
private List list;//list类型的注入
private Set set;//set类型的注入
private Map map;//map类型的注入
private Properties properties;//properties类型的注入

public Person(String name, Integer age, Car car) {
super();
System.out.println("构造方法(String name, Integer age, Car car) 方法被调用");
this.name = name;
this.age = age;
this.car = car;
}

public Person() {
super();
System.out.println("构造方法被调用");
}

public String getName() {
return name;
}

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

public Integer getAge() {
return age;
}

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


public Car getCar() {
return car;
}

public void setCar(Car car) {
this.car = car;
}


public Object[] getCars() {
return cars;
}

public void setCars(Object[] cars) {
this.cars = cars;
}



@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + ", cars=" + Arrays.toString(cars) + ", list="
+ list + ", set=" + set + ", map=" + map + ", properties=" + properties + "]";
}

public void init()
{
System.out.println("Person被初始化!");
}
public void destroy()
{
System.out.println("Person被销毁!");
}

public List getList() {
return list;
}

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

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 Properties getProperties() {
return properties;
}

public void setProperties(Properties properties) {
this.properties = properties;
}

}

(2)、Car类

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

package net.zzqd.spring.pojo;

/**
* @author zzq
* @version 创建时间:2019年5月29日 下午1:24:31
*
*/

public class Car
{
private String name;
private String color;
public Car() {
super();
System.out.println("car构造方法被调用");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Car [name=" + name + ", color=" + color + "]";
}



}

(3)、工厂方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package net.zzqd.spring.Factory;

import net.zzqd.spring.pojo.Person;

/**
* @author zzq
* @version 创建时间:2019年5月28日 下午10:28:45
*
*/

public class PersonFactory {
public static Person createPerson1()
{
System.out.println("静态工厂创建Person");
return new Person();
}
public Person createPerson2()
{
System.out.println("实例工厂创建Person");
return new Person();
}
}
配置代码

(1)、依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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:使容器创建Person的对象 -->
<!-- name:相当于变量名Person p = new Person() -->
<!-- class:类的全类名 作用域 默认singleton单例 protorype lazy-init 延迟创建-->
<!-- <bean name="p1" id="p2" class="net.zzqd.spring.pojo.Person" scope="protorype"></bean> -->
<!-- <bean name="p3" class="net.zzqd.spring.pojo.Person" init-method="init" destroy-method="destroy"></bean> -->
<!-- 静态工厂 -->
<bean name="person1" class="net.zzqd.spring.Factory.PersonFactory" factory-method="createPerson1"></bean>

<!-- 实例工厂 -->
<bean name="personFactory" class="net.zzqd.spring.Factory.PersonFactory"></bean>
<bean name="person2" factory-bean="personFactory" factory-method="createPerson2"></bean>

</beans>

(2)、控制反转

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?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 name="car" class="net.zzqd.spring.pojo.Car">
<property name="name" value="大众"></property>
<property name="color" value="黑色"></property>
</bean>

<bean name="person1" class="net.zzqd.spring.pojo.Person">
<property name="name" value="Aemon"></property>
<property name="age" value="20"></property>
<property name="car" ref="car"></property>
</bean>


<bean name="person2" class="net.zzqd.spring.pojo.Person">
<constructor-arg name="name" value="zzq"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="car" ref="car"></constructor-arg>
</bean>

<bean name="person3" class="net.zzqd.spring.pojo.Person" p:name="Aemon"
p:age="21" p:car-ref="car">

</bean>

<bean name="person4" class="net.zzqd.spring.pojo.Person" >
<property name="name" value="#{person1.name}"></property>
<property name="age" value="#{person1.age}"></property>
<property name="car" ref="car"></property>
</bean>


<bean name="person5" class="net.zzqd.spring.pojo.Person" >
<property name="name" value="Aemon"></property>
<property name="age" value="21"></property>
<property name="car" ref="car"></property>
<property name="cars">
<array>
<value>宝马</value>
<value>奔驰</value>
<value>路虎</value>
<ref bean="car"/>
</array>
</property>
<property name="list">
<list>
<value>zzq</value>
<value>zzg</value>
<value>zzz</value>
</list>
</property>

<property name="set">
<set>
<value>aa</value>
<value>bb</value>
<value>cc</value>
</set>
</property>

<property name="map">
<map>
<entry key="username" value="root"></entry>
<entry key="car" value-ref="car"></entry>
<entry key-ref="person1" value-ref="car"></entry>
</map>
</property>

<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
测试代码

(1)、依赖注入

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
package net.zzqd.spring.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
* @author zzq
* @version 创建时间:2019年5月28日 下午9:28:31
*
*/
public class InjectionTest
{

@Test
public void testProprety()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext-Injection.xml");
Person person1 = (Person)context.getBean("person1");
System.out.println(person1);
}

@Test
public void testConstructor()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext-Injection.xml");
Person person2 = (Person)context.getBean("person2");
System.out.println(person2);
}

@Test
public void testP()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext-Injection.xml");
Person person3 = (Person)context.getBean("person3");
System.out.println(person3);
}
@Test
public void testEL()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext-Injection.xml");
Person person4 = (Person)context.getBean("person4");
System.out.println(person4);
}
@Test
public void testCollection()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext-Injection.xml");
Person person5 = (Person)context.getBean("person5");
System.out.println(person5);
}
}

(二)、控制反转

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package net.zzqd.spring.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
* @author zzq
* @version 创建时间:2019年5月28日 下午9:28:31
*
*/
public class IOCTest
{
@SuppressWarnings("resource")
@Test
public void testCreatePerson()
{
//创建容器
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//查找对象
Person p = (Person)context.getBean("p");
System.out.println(p);

}
//工厂的类型,从类路径中取值
@SuppressWarnings("resource")
@Test
public void testIdAndName()
{
//创建容器
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//查找对象
Person p1 = (Person)context.getBean("p1");
Person p2 = (Person)context.getBean("p2");
System.out.println(p1);
System.out.println(p2);

}
//工厂类型,从绝对路径取值
@SuppressWarnings("resource")
@Test
public void testIdAndName1()
{
//创建容器
ApplicationContext context = new FileSystemXmlApplicationContext("C:\\DevelopTools\\JavaEEWorkSpace\\Springday1hello\\src\\ApplicationContext.xml");
//查找对象
Person p1 = (Person)context.getBean("p1");
System.out.println(p1);

}

@SuppressWarnings("resource")
@Test
public void testScope()
{
//创建容器
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//查找对象
// Person p1 = (Person)context.getBean("p1");
// Person p3 = (Person)context.getBean("p3");
//scope="singleton"时为true
//scope="prototype"时为false
//默认为singleton
//还有request session

// System.out.println(p1==p3);
//什么时候创建对象
//scope="prototype"时,在容器启动时不创建对象,当获取对象时才创建
//scope="singleton"时,在容器启动时创建对象,只创建一个

//是否延迟创建对象
// <bean name="p3" class="net.zzqd.spring.pojo.Person" scope="singleton" lazy-init="true"></bean>
//延迟创建对象,容器启动时不创建,获取时在创建
//lazy-init="false" 默认值,容器启动时立即创建
//以上只对单例有效
}

@SuppressWarnings("resource")
@Test
public void testInitAndDestroy()
{
//容器

AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//主动调用destroy方法执行销毁
//context.destroy();
context.close();
}


/*
*
一、无参构造函数
二、有参构造函数
参考后面的依赖注入
三、实例工厂方法
四、静态工厂方法
*/
@Test
public void testStaticFactory()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Person person1 = (Person)context.getBean("person1");
}
// <bean name="person1" class="net.zzqd.spring.Factory.PersonFactory" factory-method="createPerson1"></bean>
//静态工厂


@Test
public void testStaticFactory2()
{
AbstractApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
}
}

AOP

AOP(Aspect Oriented Programming)

​ AOP为Aspect Oriented Programming的缩写、意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合降低,提高程序的可重用性,同时提高了开发的效率

AOP思想:横向重复、纵向抽取

底层实现

​ Spring的AOP底层用到了两种代理机制:

​ JDK的动态代理:针对实现了接口的类产生代理。

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

AOP开发相关术语
  • Joinpoint(连接点):所谓连接点是指那些被拦截的点,在spring中,这些点指的是方法,因为spring只支持方法类型的连接点(可以被切入的点)
  • Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义,(已知被切入的点)
  • Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)
  • Introduction(引介):引介是一种特殊的通知在不改类代码的前提下,Introduction可以在运行期为类动态添加一些方法或Field。
  • Aspect(切面):是切入点和通知(引介)的结合
  • Targer(目标对象):代理的目标对象
  • Proxy(代理):一个类被AOP织入增强后,就产生了一个结果代理类。
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用预编译期织入和类装载期织入
代码测试
业务代码:

(1)、service接口代码

1
2
3
4
5
6
7
8
9
10
11
12
package net.zzqd.spring.aop.service;
/**
* @author zzq
* @version 创建时间:2019年5月30日 下午6:23:15
*
*/
public interface UserService {
public void save(String name);
public void delate();
public void update();
public void select();
}

(2)、service实现类

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
package net.zzqd.spring.aop.service;
/**
* @author zzq
* @version 创建时间:2019年5月30日 下午6:23:15
*
*/
public class UserServiceImpl implements UserService {

@Override
public void save(String name) {
System.out.println("保存用户");
}

@Override
public void delate() {
System.out.println("删除用户");
}

@Override
public void update() {
System.out.println("更新用户");
}

@Override
public void select() {
System.out.println("查询用户");
}

}
配置文件代码
  1. 用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: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.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!-- 目标对象 -->
    <bean name="userService" class="net.zzqd.spring.aop.service.UserServiceImpl"></bean>
    <!-- 通知对象 -->
    <bean name="transactionAdvice" class="net.zzqd.spring.aop.advice.TransactionAdvice"></bean>
    <!-- 将通知对象织入目标对象 -->
    <aop:config>
    <!-- 选择切入点 -->
    <aop:pointcut expression="execution(* net.zzqd.spring.aop.service..*ServiceImpl.*(..))" id="pointcut"/>
    <aop:aspect ref="transactionAdvice">
    <aop:before method="before" pointcut-ref="pointcut"/>
    <aop:after-returning method="afterReturnning" pointcut-ref="pointcut"/>
    <aop:after method="after" pointcut-ref="pointcut"/><!--无论是否出现异常都执行-->
    <aop:around method="around" pointcut-ref="pointcut"/>
    <aop:after-throwing method="afterException" pointcut-ref="pointcut"/>

    </aop:aspect>
    </aop:config>

    </beans>
  1. 使用注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?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.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!-- 目标对象 -->
    <bean name="userService" class="net.zzqd.spring.aop.service.UserServiceImpl"></bean>
    <!-- 通知对象 -->
    <bean name="transactionAdvice" class="net.zzqd.spring.aop.advice.TransactionAdvice"></bean>
    <!-- 开启织入注解 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>


    </beans>
  2. 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 net.zzqd.spring.aop.advice;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;

    /**
    * @author zzq
    * @version 创建时间:2019年5月30日 下午6:28:06
    *
    */
    @Aspect
    public class TransactionAdvice {
    //前置通知:在目标方法之前调用
    //后置通知:(如果出现异常就不调用)在目标方法之后调用
    //后置通知:(无论是否出现都会调用)在目标方法之后调用
    //环绕通知:在目标执行方法之前之后调用
    //异常通知:出项异常则调用
    @Pointcut("execution(* net.zzqd.spring.aop.service..*ServiceImpl.*(..))")
    public void point() {}

    @Before("TransactionAdvice.pointcut()")
    public void before()
    {
    System.out.println("前置通知被执行");
    }
    @AfterReturning("TransactionAdvice.pointcut()")
    public void afterReturnning()
    {
    System.out.println("后置通知被执行(如果出现异常就不调用)");
    }
    @After("TransactionAdvice.pointcut()")
    public void after()
    {
    System.out.println("后置通知被执行");
    }
    @AfterThrowing("TransactionAdvice.pointcut()")
    public void afterException()
    {
    System.out.println("异常通知被执行");
    }
    @Around("TransactionAdvice.pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable
    {
    System.out.println("环绕通知前");
    Object proceed = point.proceed();//调用目标方法
    System.out.println("环绕通知后");
    return proceed;
    }
    }
测试代码
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
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import net.zzqd.spring.aop.service.UserService;

/**
* @author zzq
* @version 创建时间:2019年5月31日 上午9:39:05
*
*/
//创建测试容器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest
{
@Resource(name="userService")
private UserService userService;

@Test
public void testUpdate()
{
userService.update();
}
@Test
public void testSave()
{
userService.save("AemonZhu");
}
@Test
public void testDelete()
{
userService.delate();
}
}
Like • 1 Liked 1 Comments 所有评论
  • zqnh commented on Fri May 24 2019

    我是作者,博客评论系统初始化成功,纪念一下!