Spring的依赖注入和AOP使用详解
一. 需要的POM.xml依赖
1 |
|
二. DI依赖注入
1. 构造器注入
1 实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyBean {
private Long id;
private String username;
private YouBean youBean;
public MyBean(Long id, String username) {
this.id = id;
this.username = username;
}
public MyBean(Long id, String username, YouBean youBean) {
this.id = id;
this.username = username;
this.youBean = youBean;
}
}1
2
3
4
5
public class YouBean {
private Long id;
private String username;
}applicationContext.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
<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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 默认使用无参构造 创建对象 -->
<!-- <bean id="myBean" class="com.lqs.constructor.domain.MyBean2"/>-->
<!--有参构造-->
<bean id="myBean" class="com.lqs.constructor.domain.MyBean">
<!-- 索引 -->
<!-- <constructor-arg index="0" value="100"/>-->
<!-- <constructor-arg index="1" value="root"/>-->
<!--属性名赋值-->
<!-- <constructor-arg name="id" value="10086"/>-->
<!-- <constructor-arg name="username" value="admin"/>-->
<!-- 通过类型注入 -->
<!-- <constructor-arg type="java.lang.Long" value="11003"/>-->
<!-- <constructor-arg type="java.lang.String" value="coderyeah"/>-->
<constructor-arg name="id" value="10086"/>
<constructor-arg name="username" value="admin"/>
<!-- <constructor-arg name="youBean" ref="youBean"/>-->
<!--内部bean构造器注入,不需要指定ID 但是每次地址值不同-->
<constructor-arg name="youBean">
<bean class="com.lqs.constructor.domain.YouBean"/>
</constructor-arg>
</bean>
<bean id="youBean" class="com.lqs.constructor.domain.YouBean"/>
</beans>
2. property-setter注入
2.1 Bean
1 |
|
1 | public class OtherBean { |
2.2 简单属性
1 | <bean id="myBean2" class="com.lqs.property.domain.MyBean2"> |
2.3 集合属性
1 | <bean id="myBean2" class="com.lqs.property.domain.MyBean2"> |
2.4 properties
1 | <bean id="myBean2" class="com.lqs.property.domain.MyBean2"> |
三. AOP
1. 什么是AOP
AOP:全称是Aspect Oriented Programming 即:面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
2. AOP实现方式
使用动态代理技术。
3. 代理模式
- SpringAOP底层是使用了代理模式对我们的方法进行增强;
- 代理模式分类:
- 静态代理:作用不大,只能代理或增强一个方法,比较鸡肋
- 动态代理:功能强大,有两种方案,Spring会自动选择使用那种方案
- 方案一:原生JDK的方式,在我们的类实现了接口之后,就会使用这种方式,spring使用JDK的java.lang.reflect.Proxy类代理,推荐使用,更加解耦
- 方案二:我如果我们的类没有实现接口,那么Spring使用CGLIB库生成目标对象的子类。
四. aop的xml实现方式
Bean
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
public class TxManager {
public void begin() {
System.out.println("开启事务......");
}
public void commit() {
System.out.println("提交事务......");
}
public void rollback(Throwable e) {
System.out.println("回滚事务......");
System.out.println(e.getMessage());
}
public void close() {
System.out.println("关闭连接......");
}
//环绕通知
public void around(ProceedingJoinPoint joinPoint) {
begin();
try {
joinPoint.proceed();
commit();
} catch (Throwable e) {
e.printStackTrace();
rollback(e);
} finally {
close();
}
}
}接口
1
2
3
4
5
6
7
8
9package com.lqs.aop_xml.service;
public interface IUserService {
void add();
void update();
void delete();
}配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<!-- aop配置 -->
<aop:config>
<!-- 声明切点
*:方法返回不限制
..:参数不做限制
expression="execution(* com.lqs.aop_xml.service.IUserService.add(..)
-->
<aop:pointcut id="pointcut" expression="execution(* com.lqs.aop_xml.service.IUserService.*(..))"/>
<!-- 配置切面 增强类 -->
<aop:aspect ref="txManager">
<!-- 在add()方法之前执行begin操作 -->
<!-- <aop:before method="begin" pointcut-ref="pointcut"/>-->
<!-- 业务方法之后 执行 -->
<!-- <aop:after-returning method="commit" pointcut-ref="pointcut"/>-->
<!--发生异常-->
<!-- <aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="e"/>-->
<!-- 最后执行 -->
<!-- <aop:after method="close" pointcut-ref="pointcut"/>-->
<!-- 环绕通知强大 可代替以上通知 -->
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
五. aop的注解实现方式
配置注解扫描路径和开启动态代理
1
2
3
4<context:component-scan base-package="com.lqs.aop_xml"/>
<context:component-scan base-package="com.lqs.aop_anno"/>
<!--开启AspectJ 自动代理-->
<aop:aspectj-autoproxy/>增强类
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
52package com.lqs.aop_anno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//定义一个切面
public class TxManager2 {
//定义切点 空的方法体
public void pointCut() {
}
// @Before("pointCut()")
public void begin() {
System.out.println("开启事务......");
}
// @AfterReturning("pointCut()")
public void commit() {
System.out.println("提交事务......");
}
// @AfterThrowing(value = "pointCut()", throwing = "e")
public void rollback(Throwable e) {
System.out.println("回滚事务......");
System.out.println(e.getMessage());
}
// @After("pointCut()")
public void close() {
System.out.println("关闭连接......");
}
//环绕通知 不与其它通知一起用
public void around(ProceedingJoinPoint joinPoint) {
begin();
try {
joinPoint.proceed();
commit();
} catch (Throwable e) {
e.printStackTrace();
rollback(e);
} finally {
close();
}
}
}
六. spring创建bean的四种方式
普通方式-通过公共无参进行实例化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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">
<!-- spring创建bean的四种方式:
1.以前的方式,在xml中进行配置,或者是注解方式进行扫描
2.使用静态方法工厂模式:当你要使用的类无法通过new创建出来,而只能通过工厂获取,比如sqlSession
3.使用普通方法工厂模式
4.使用FacctoryBean方式
-->
<bean id="myBean" class="com.lqs.bean.domain.MyBean"/>
</beans>集成静态简单工厂
1
2
3
4
5
6
7// 此工厂生产MyBean
public class MyBeanFactory {
// 此方法是一个静态方法,用来生产MyBean
public static MyBean getMyBean(){
return new MyBean();
}
}1
2<!-- 注入的是getMyBean方法的返回值 不是MyFactoryBean -->
<bean class="com.lqs.bean.MyFactoryBean" factory-method="getMyBean"/>集成实例简单工厂
与第二种的区别就是,当你的工厂方法不是静态方法时,无法通过类名.方法名调用
1
2
3
4
5
6
7
8
9public class MyFactoryBean {
// public static MyBean getMyBean() {
// return new MyBean();
// }
public MyBean getMyBean() {
return new MyBean();
}
}1
2
3<!-- 普通方法创建bean -->
<bean id="myFactoryBean" class="com.lqs.bean.MyFactoryBean"/>
<bean id="myBean" factory-bean="myFactoryBean" factory-method="getMyBean"/>
使用FactoryBean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package com.lqs.bean;
import com.lqs.bean.domain.MyBean;
import org.springframework.beans.factory.FactoryBean;
// FactoryBean<MyBean>:实现一个FactoryBean接口,并指定要生产的Bean对象
public class MyBeanFactoryBean implements FactoryBean<MyBean> {
// 此方法指定你要生产的bean对象
public MyBean getObject() throws Exception {
return new MyBean();
}
// 此方法指定你生产的bean的类型,必须指定否则报错
public Class<?> getObjectType() {
return MyBean.class;
}
// 此方法指定你生产的bean是否是单例的,默认false
public boolean isSingleton() {
return true;
}
}1
2<!--使用MyBeanFactoryBean方式创建bean-->
<bean id="myBeanFactoryBean" class="com.lqs.bean.MyBeanFactoryBean"/>
七. FactoryBean和BeanFactory的区别
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
评论