IOC与AOP
IOC:控制反转,将实例的生命周期交由Spring框架管理,可通过XML文件定义需要管理的类(<bean>标签定义、FactoryBean定义、组件注解扫描)
<?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" xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.jason.lee.ioc" use-default-filters="false">
<!--扫描筛选-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
<!--构造器注入 参数默认顺序对应 scope作用域为单例,容器初始化时创建-->
<!--1、构造器 2、依赖注入 3、初始化init 4、使用 5、销毁destroy-->
<bean id="example01" class="com.jason.lee.ioc.Example" scope="singleton"
init-method="init" destroy-method="destroy">
<constructor-arg value="1"/>
<constructor-arg value="example01" index="1" type="java.lang.String"/>
</bean>
<!--Setter属性注入 存在无参构造函数和对应属性的set方法-->
<bean id="example02" class="com.jason.lee.ioc.Example">
<property name="id" value="2"/>
<property name="name" value="example02"/>
</bean>
<!--Setter属性注入 p命名空间简化写法-->
<bean id="example03" class="com.jason.lee.ioc.Example" p:id="3" p:name="example03"/>
<bean id="test01" class="com.jason.lee.ioc.MyBean">
<property name="id" value="1"/>
<property name="name" value="test01"/>
<!--ref引用外部bean-->
<property name="example" ref="example01"/>
</bean>
<bean id="example04" class="com.jason.lee.ioc.Example">
<constructor-arg value="4"/>
<constructor-arg value="example04" index="1" type="java.lang.String"/>
<!--注入集合-->
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="array">
<array>
<value>4</value>
<value>5</value>
</array>
</property>
<property name="map">
<map>
<entry>
<key>
<value>key</value>
</key>
<value>value</value>
</entry>
</map>
</property>
</bean>
<bean id="example05" class="com.jason.lee.ioc.Example">
<property name="list" ref="list"/>
</bean>
<!--集合bean-->
<util:list id="list">
<value>6</value>
<value>7</value>
<value>8</value>
</util:list>
<bean id="test02" class="com.jason.lee.ioc.MyBean">
<property name="id" value="2"/>
<property name="name" value="test02"/>
<property name="example" ref="example01"/>
<!--通过级联属性设置值-->
<property name="example.id" value="0"/>
<property name="example.name" value="xxx"/>
</bean>
<bean id="test03" class="com.jason.lee.ioc.MyBean">
<property name="id" value="3"/>
<property name="name" value="test03"/>
<property name="example">
<!--内部bean-->
<bean class="com.jason.lee.ioc.Example">
<property name="id" value="0"/>
<property name="name" value="xxx"/>
</bean>
</property>
</bean>
<!--工厂-->
<bean id="myFactory" class="com.jason.lee.ioc.MyFactoryBean"/>
<!--自动注入-->
<bean id="employee" class="com.jason.lee.ioc.Employee" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="employee"/>
</bean>
<bean id="car" class="com.jason.lee.ioc.Car" p:brand="Benz" p:price="100000"/>
</beans>
public class MyFactoryBean implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
Car car = new Car();
car.setBrand("BMW");
car.setPrice(2000000D);
return car;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
@Component
public class Bean {
@Override
public String toString() {
return "Bean to String";
}
}
AOP:面向切面编程,利用动态代理实现业务逻辑与横切逻辑解耦
1、业务接口与实现类
public interface MathIntf {
int add(int i, int j);
int div(int i, int j);
}
@Component("mathImpl")
public class MathIntfImpl implements MathIntf {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println(result);
return result;
}
@Override
public int div(int i, int j) {
int result = i/j;
System.out.println(result);
return result;
}
}
2、AOP实现
2.1、XML配置
<?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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.jason.lee.aop.xml"/>
<aop:config>
<!--切面 = 切点 + 通知-->
<aop:aspect id="myAspect" ref="myLogger">
<!--切点:何处-->
<aop:pointcut id="myPointcut" expression="execution(* com.jason.lee.aop.xml.*.*(..))"/>
<!--<aop:before method="before" pointcut="execution(* com.jason.lee.spring-aop-annotation.xml.*.*(..))"/>-->
<!--通知:何时、内容-->
<aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
</beans>
@Component
public class MyLogger {
public static void before() {
System.out.println("前置通知");
}
public static void after() {
System.out.println("后置通知");
}
}
2.2、注解方式
<?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: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">
<context:component-scan base-package="com.jason.lee.aop.annotation"/>
<!--开启aspectj的自动代理功能-->
<aop:aspectj-autoproxy/>
</beans>
@Component
@Aspect //标注当前类为切面
@Order(value = 1) //定义切面作用的优先级 【值越小优先级越高】
public class MyAspect {
//定义公共切入点
@Pointcut(value = "execution(* com.jason.lee.aop.annotation.*.*(..))")
public void pointCut(){}
/**
* @Before 将方法指定为前置通知 【方法执行前】
* 必须设置value,其值为切入点表达式(定位被作用的位置——连接点)
* joinPoint 获取连接点信息
*/
//@Before(value = "execution(public int com.jason.lee.aop.annotation.MathIntfImpl.add(int,int))")
// * com.jason.lee.aop.*.*(..)
// 任意访问修饰符 任意类 任意方法 任意参数
@Before(value = "execution(* com.jason.lee.aop.annotation.*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println("前置通知——Method: " + name + ", Args: " + Arrays.toString(args));
}
/**
* 后置通知相当于作用在finally语句块 即无论是否异常均执行后置逻辑
* @param joinPoint
*/
@After(value = "pointCut()")
public void afterMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println("后置通知——Method: " + name + ", Args: " + Arrays.toString(args));
}
/**
* 返回通知 【方法执行后】
* @param joinPoint
* @param result
*/
@AfterReturning(value = "execution(* com.jason.lee.aop.annotation.*.*(..))",returning = "result")
public void afterReturningMethod(JoinPoint joinPoint,Object result) {
String name = joinPoint.getSignature().getName();
System.out.println("返回通知——Method: " + name + ", Result: " + result);
}
@AfterThrowing(value = "execution(* com.jason.lee.aop.annotation.*.*(..))",throwing = "exception")
public void afterThrowingMethod(JoinPoint joinPoint,Exception exception) {
String name = joinPoint.getSignature().getName();
System.out.println("异常通知——Method: " + name + ", Exception: " + exception);
}
/**
* 环绕通知
* @param proceedingJoinPoint
* @return
*/
@Around(value = "execution(* com.jason.lee.aop.annotation.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {
Object result;
try {
// 前置通知
System.out.println("前置通知");
result = proceedingJoinPoint.proceed(); // 执行方法
// 返回通知
System.out.println("返回通知");
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
// 异常通知
System.out.println("异常通知");
} finally {
// 后置通知
System.out.println("后置通知");
}
return -1;
}
}