IOC是控制反转:
java的bean或者pojo类一般是自主使用new进行创建,现在通过使用spring框架,将java类的创建权限
反转给spring容器,这就是控制反转;
从被管理的类的角度的说的;
DI依赖注入:
spring容器根据被托管的类或者变量之间的依赖关系,而注入这个类的实例对象或者变量的值;
从spring容器的角度说的;
1、属性依赖注入
需要提供属性的setter方法接口;
2、构造方法依赖注入
需要提供对应参数个数的重载的构造方法
3、工厂类依赖注入
需要提供对应的工厂类;
注意:spring进行依赖注入时的依赖关系一般指的的是 类与类之间的 组合关系;
想添加日志或者其他公共操作,如果采取创建工具类,把公共操作放在工具类的方法中,违背了开放-封闭以及单一职责的设计原则
Java设计原则:
https://blog.csdn.net/albenxie/article/details/72371102
AOP采用自动化的方式,并不需要修改源代码,完成公共的操作,实现基于动态代理机制,遵循了开闭原则和单一职责原则
Java中三种代理模式:
https://www.cnblogs.com/jie-y/p/10732347.html
参考文档:Spring–AOP详解
https://www.open-open.com/lib/view/open1338175216901.html
https://blog.csdn.net/q982151756/article/details/80513340
AOP里面几个重要名词概述的概念:
术语 | 含义 |
---|---|
Aspect(切面) | 切入点+通知 |
joinPoint(连接点) | 目标对象,所有可以增强的方法 |
Advice(通知/增强) | 增强代码 |
PointCut(切入点) | 目标对象,将要和已经增强的方法 |
Introduction(引入) | 声明某个方法或字段 |
Target(目标对象) | 被代理的对象 |
AOP 代理(AOp Proxy) | AOP框架创建的对象用来实现切面 |
Weaving(织入) | 将通知应用到切入点的过程 |
参考原文地址:https://blog.csdn.net/qq_39507327/article/details/81507224
概念的关系图:
<!--aop依赖包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
//定义切面类
public class Logging {
//在被代理对象方法的前面加公共操作
public void before(){
System.out.println("执行了before");
}
//在被代理对象方法的后面加公共操作
public void after(){
System.out.println("执行了after");
}
}
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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
<!--开启注解的支持-->
<context:annotation-config></context:annotation-config>
<!--指定扫描包的路径-->
<context:component-scan base-package="com.test"></context:component-scan>
<!--定义切面类:把切面类放到Spring容器-->
<bean id="logging" class="com.test.aspect.Logging"></bean>
<!--配置切面:配置切入的规则-->
<aop:config>
<!--配置切面-->
<aop:aspect id="myAspect" ref="logging"><!--ref:注入的是bean的实例-->
<!--配置切入点:切入的位置-->
<aop:pointcut id="poointcut" expression="execution(* com.test.service.*.*(..))"></aop:pointcut>
<!--任意返回值类型 任意类 任意方法 多种参数-->
<!--切入的时机:方法执行前还是执行后加等,指定把切面类中哪个公共操作进行通知-->
<aop:before method="before" pointcut-ref="poointcut"></aop:before><!--前置增强-->
<!--pointcut-re引用上面的切入点-->
<aop:after method="after" pointcut-ref="poointcut"></aop:after><!--后置增强-->
</aop:aspect>
</aop:config>
1) Spring配置文件中
<!--开启注解的支持-->
<context:annotation-config></context:annotation-config>
<!--指定扫描包的路径-->
<context:component-scan base-package="com.test"></context:component-scan>
<!--定义切面类:把切面类放到Spring容器-->
<bean id="logging" class="com.test.aspect.Logging"></bean>
<!--配置切面:配置切入的规则-->
<aop:config>
<!--配置切面-->
<aop:aspect id="myAspect" ref="logging"><!--ref:注入的是bean的实例-->
<!--配置切入点:切入的位置--><!--aop:pointcut配置切入点,expression配置表达式-->
<aop:pointcut id="poointcut" expression="execution(* com.test.service.*.*(..))"></aop:pointcut>
<!--任意返回值类型 任意类 任意方法 多种参数-->
<aop:after-returning method="after" pointcut-ref="poointcut"></aop:after-returning><!--返回后增强-->
<aop:around method="around" pointcut-ref="poointcut"></aop:around><!--环绕增强-->
<aop:after-throwing method="afterThrowing" pointcut-ref="poointcut"></aop:after-throwing>
<!--AOP的AfterThrowing处理虽然可以对目标方法的异常进行处理,但这种处理与直接使用catch捕捉不同,catch捕捉意味着完全处理该异常,
如果catch块中没有重新抛出新的异常,则该方法可能正常结束;而AfterThrowing处理虽然处理了该异常,但它不能完全处理异常,
该异常依然会传播到上一级调用者,即JVM。-->
</aop:aspect>
</aop:config>
2) 切面类中增加方法
//定义切面类
public class Logging {
//在被代理对象方法的前面加公共操作
public void before(){
System.out.println("执行了before");
}
//在被代理对象方法的后面加公共操作
public void after(){
System.out.println("执行了after");
}
//在被代理对象方法的前后加公共操作
public void around(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("方法执行前的操作:--------------");
//执行主要方法
Object result=joinPoint.proceed();
System.out.println("方法执行后的操作:--------------");
System.out.println("执行了"+joinPoint.getTarget()+"方法,方法的返回值是:"+result+"\t方法的名称:"+joinPoint.getSignature().getName());
}
public void afterThrowing(){
System.out.println("执行了afterThrowing\n发生了系统异常");
}
}
参考资料:https://blog.csdn.net/m0_37626813/article/details/78558010
1、@controller 控制器(注入服务)
用于标注控制层,相当于struts中的action层
2、@service 服务(注入dao)
用于标注服务层,主要用来进行业务的逻辑处理
3、@repository(实现dao访问)
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件.
4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的
)
泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。
案例:
<context:component-scan base-package=”com.*”>
上面的这个例子是引入Component组件的例子,其中base-package表示为需要扫描的所有子包。
共同点:被@controller 、@service、@repository 、@component 注解的类,都会把这些类纳入进spring容器中进行管理
参考资料:
https://www.jianshu.com/p/f6fd176ff42c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
1) Spring配置文件中:
<!--开启注解的支持-->
<context:annotation-config></context:annotation-config>
<!--指定扫描包的路径-->
<context:component-scan base-package="com.test"></context:component-scan>
<!--配置AOP动态处理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2) 切面类中添加注解
//定义切面类
/*@Component把普通pojo实例化到spring容器中,相当于配置文件中的 */
//切面类加入IOC容器
@Component
@Aspect
/*aop:aspect配置切面,ref引入IOC容器中的切面类*/
public class Logging {
//在被代理对象方法的前面加公共操作
/*aop:before前置增强*/
@Before("execution(* com.test.service.*.*(..))")
public void before(){
System.out.println("执行了before");
}
//在被代理对象方法的后面加公共操作
@After("execution(* com.test.service.*.*(..))")
public void after(){
System.out.println("执行了after");
}
//在被代理对象方法的前后加公共操作
@Around("execution(* com.test.service.*.*(..))")
public void around(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("方法执行前的操作:--------------");
//执行主要方法
Object result=joinPoint.proceed();
System.out.println("方法执行后的操作:--------------");
System.out.println("执行了"+joinPoint.getTarget()+"方法,方法的返回值是:"+result+"\t方法的名称:"+joinPoint.getSignature().getName());
}
@AfterThrowing("execution(* com.test.service.*.*(..))")
public void afterThrowing(){
System.out.println("执行了afterThrowing\n发生了系统异常");
}
}
//UserService对象
@Test
public void testUserService(){
//读取String配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("application-context.xml");
//获取UserService对象
UserService userService=(UserService)context.getBean("userService");
//调用UserService对象的getCount方法
userService.getCount();
}
测试结果
方法执行前的操作:--------------
执行了before
执行了UserService的getCount方法!!
执行了UserDao的getCount方法!!
方法执行后的操作:--------------
执行了com.test.service.UserServiceImpl@5c7bfdc1方法,方法的返回值是:1 方法的名称:getCount
执行了after
Process finished with exit code 0