Spring系列(二)自动装配和AOP
1. 自动装填
自动装配:
- byName:会自动在容器上下文中查找,和自己set方法后面的值对应的bean id
- byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean
1 2 3 4 5
| <bean id="people" class="top.qwwq.pojo.People" autowire="byName"> <property name="name" value="EnderKC"/> <property name="dog" ref="dog"/> <property name="cat" ref="cat"/> </bean>
|
自动装配注解:
@Autowired 自动装配 Spring的包
@Resource 自动装配 javax的包
@Nullable 允许为null
2. 注解开发
在Spring4之后,要使用注解开发,必须要保证aop包导入了

使用注解需要导入注解的支持
Spring官网
1 2 3 4 5 6 7 8 9 10 11 12
| <?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
|
- @Component 放在类上,说明这个类被Spring管理了 等价于
1
| <bean id="user" class="top.qwwq.pojo.User"/>
|
- @Value 给属性注入值,等价于 👇
1 2 3
| <bean id="user" class="top.qwwq.pojo.User"> <property name="name" value="EnerKC"/> </bean>
|
- @Scope 设置作用域
bean
属性如何注入
1 2 3 4 5
| @Component public class User { @Value("EnderKC") public String name; }
|
衍生的注解
小结
XML与注解
- xml更加万能,方便维护
- 不是自己的类引用不了,维护相对复杂
XML与注解最佳实践:
- xml用来管理bean
- 直接只负责完成属性的注入
- 我们在使用的过程中,只需要注意一个问题:必须让注解生效,要开启注解支持
3. 使用JAVA的方式配置
我们现在要完全不使用Spring的xml配置了,全权交给Java来做
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能
MyConfig.java 配置类
1 2 3 4 5 6 7 8 9 10 11
| @Configuration @Import(MyConfig2.class) public class MyConfig { @Bean public User getUser(){ return new User(); } }
|
User.java 实体类
1 2 3 4 5 6
| @Data public class User { @Value("EnderKC") private String name; }
|
MyTest.java 测试类
1 2 3 4 5 6 7 8 9
| public class MyTest { @Test public void test1(){ ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); User user = context.getBean("getUser", User.class); System.out.println(user); } }
|
这种纯java的配置方式,在SpringBoot中随处可见!
4. 代理模式
为什么要学习代理模式?
因为这就是SpringAop的底层 【SpringAOP和SpringMVC】
代理模式的分类:

4.1 静态代理
角色分析
- 抽象角色:一般会使用接口或者抽象类来解决
- 真是角色:被代理的人
- 代理角色:代理真实角色,代理真是角色后,我们一般会做一些附属操作
- 客户:访问代理对象
代码步骤:
- 接口
1 2 3 4
| public interface Rent { void rent(); }
|
- 真实角色
1 2 3 4 5 6 7
| public class Host implements Rent{ @Override public void rent() { System.out.println("房东要出租房子"); } }
|
- 代理角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Proxy implements Rent{ private Host host;
@Override public void rent() { host.rent(); } public void seeHouse(){ System.out.println("中介带你看房"); } public void fare(){ System.out.println("中介收中介费"); } public void hetong(){ System.out.println("中介签合同"); } }
|
- 客户端访问代理角色
1 2 3 4 5 6 7 8 9 10
| public class Client { public static void main(String[] args) { Host host = new Host(); Proxy proxy = new Proxy(host); proxy.rent(); } }
|
代理模式的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公众的业务
- 公共也就交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真是角色,就要产生一个代理角色,代码量会翻倍,开发效率会低
4.2 加深理解
聊聊AOP

4.3 动态代理
- 动态代理和静态代理角色一样
- 动态代理类是动态生成的,不是我们直接写好的!
- 动态代理分为两大类:
- 基于接口的动态代理
- 基于类的动态代理
- Java字节码实现 JavaAssist
需要了解两个类: Proxy InvocationHandler
万能动态代理类实现代码:
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
| public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Rent target) { this.target = target; }
public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this); }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args); }
}
|
客户使用代理 代码实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Client { public static void main(String[] args) { Host host = new Host(); ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setRent(host);
Rent proxy = (Rent) pih.getProxy();
proxy.rent(); } }
|
动态代理的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公众的业务
- 公共也就交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是对应一类业务
- 一个动态代理类可以代理多个接口,只要实现了同一个接口即可!
5. AOP
5.1 什么是AOP
AOP (Aspect Oriented Programming)
意为: 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术AOP是OOP的延续,
是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种行生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,
同时提高了开发的效率。

5.2 AOP在Spring中的作用
提供声明式事务,允许用户自定义切面
- 横切关注点: 跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等 ….
- 切面 (ASPECT) : 横切关注点 被模块化 的特殊对象。即,它是一个类 【比如说log】
- 通知 (Advice) :切面必须要完成的工作。即,它是类中的一个方法 【比如说log中的方法】
- 目标 (Target) : 被通知对象 【一个接口,或者一个方法】
- 代理 (Proxy) : 向目标对象应用通知之后创建的对象 【生成的代理类】
- 切入点 (PointCut) : 切面通知 执行的“地点”的定义
- 连接点 (JointPoint) : 与切入点匹配的执行点

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

使用AOP织入,需要导入一个依赖包
1 2 3 4 5 6 7
| <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.19</version> <scope>runtime</scope> </dependency>
|
如果我们想写一个日志的功能
方式一:使用Spring的接口
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
| <?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 https://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">
<context:annotation-config/>
<bean id="userService" class="top.qwwq.service.UserServiceImpl"/> <bean id="log" class="top.qwwq.log.Log"/> <bean id="afterLog" class="top.qwwq.log.AfterLog"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* top.qwwq.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
|
创建包 log service

AfterLog.java
1 2 3 4 5 6 7
| public class AfterLog implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了"+method.getName()+"返回结果为:"+returnValue); } }
|
Log.java
1 2 3 4 5 6 7 8 9 10
| public class Log implements MethodBeforeAdvice {
@Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName() +"的"+method.getName()+"被执行了"); } }
|
UserService.java 接口
1 2 3 4 5 6
| public interface UserService { public void add(); public void delete(); public void update(); public void query(); }
|
UserServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class UserServiceImpl implements UserService{
@Override public void add() { System.out.println("增加了一个用户"); }
@Override public void delete() { System.out.println("删除了一个用户"); }
@Override public void update() { System.out.println("更新了一个用户"); }
@Override public void query() { System.out.println("查找了一个用户"); } }
|
MyTest.java
1 2 3 4 5 6 7 8 9
| public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add();
} }
|
方式二:使用自定义类 【没有第一中方法灵活】
新建diy包
DiyPointCut.java
1 2 3 4 5 6 7 8
| public class DiyPointCut { public void before(){ System.out.println("========方法执行前========"); } public void after(){ System.out.println("========方法执行后========"); } }
|
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
| <?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 https://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">
<context:annotation-config/>
<bean id="userService" class="top.qwwq.service.UserServiceImpl"/> <bean id="log" class="top.qwwq.log.Log"/> <bean id="afterLog" class="top.qwwq.log.AfterLog"/>
<bean id="diy" class="top.qwwq.diy.DiyPointCut"/> <aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="pointcut" expression="execution(* top.qwwq.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
</beans>
|
Test输出
1 2 3
| ========方法执行前======== 增加了一个用户 ========方法执行后========
|
方式三:注解实现AOP
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
| <?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 https://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">
<context:annotation-config/>
<bean id="userService" class="top.qwwq.service.UserServiceImpl"/> <bean id="log" class="top.qwwq.log.Log"/> <bean id="afterLog" class="top.qwwq.log.AfterLog"/>
<bean id="annotationPointCut" class="top.qwwq.diy.AnnotationPointCut"/>
<aop:aspectj-autoproxy/>
</beans>
|
AnnotationPointCut.java
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
| package top.qwwq.diy;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; 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 AnnotationPointCut { @Before("execution(* top.qwwq.service.UserServiceImpl.*(..))") public void before(){ System.out.println("========执行方法前===========");
} @After("execution(* top.qwwq.service.UserServiceImpl.*(..))") public void after(){ System.out.println("========执行方法后==========="); } @Around("execution(* top.qwwq.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) { System.out.println("========环绕前======="); Signature signature = jp.getSignature(); System.out.println(signature); try { jp.proceed(); } catch (Throwable e) { throw new RuntimeException(e); }
System.out.println("========环绕后=======");
} }
|
其他的文件什么都不用改,直接运行就好
MyTest.java
1 2 3 4 5 6 7 8
| public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); } }
|