ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 1. AOP > * AOP :面向切面编程思想 > 1. 横向重复代码,纵向抽取。 > * 动态代理: > 1. 可以体现AOP思想 > 2. 对对象中的方法进行增强 > * Spring aop开发 > 1. Spring封装了动态代理的代码,我们就不需要手写动态代理代码 > 2. 还封装了cglib代理 > 3. 1和2使Spring对任何类进行增强 ![](https://box.kancloud.cn/ce31c3d2345d2f016c2f401bb38a4f96_986x401.png) 有接口优先使用动态代理,否则使用cglib代理 ### 1.1 动态代理 测试 代理类接口 ~~~ package com.aixin.daili; /** * Created by dailin on 2017/12/12. */ public interface UserService { void save(); void update(); void delete(); void select(); } ~~~ 代理实现类 ~~~ package com.aixin.daili; /** * Created by dailin on 2017/12/12. */ public class UserServiceImpl implements UserService { public void save() { System.out.println("保存用户"); } public void update() { System.out.println("更新用户"); } public void delete() { System.out.println("删除用户"); } public void select() { System.out.println("查找用户"); } } ~~~ 代理工厂 ~~~ package com.aixin.c_proxy; import com.aixin.daili.UserService; import com.aixin.daili.UserServiceImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created by dailin on 2017/12/12. */ public class UserServiceProxyFactory implements InvocationHandler{ private UserService us; //被代理对象 public void setUs(UserService us) { this.us = us; } public UserServiceProxyFactory(UserService us) { this.us = us; } public UserService getUserServiceProxy(){ //生成动态代理对象 UserService usPrxoy = (UserService)Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), this); return usPrxoy; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("打开事务!"); Object obj = method.invoke(us, args); System.out.println("提交事务"); return obj; } } ~~~ 测试 ~~~ package springTest.ProxyTest; import com.aixin.c_proxy.UserServiceProxyFactory; import com.aixin.daili.UserService; import com.aixin.daili.UserServiceImpl; import org.junit.Test; /** * Created by dailin on 2017/12/12. */ public class test { @Test public void testDongtai() { UserService us = new UserServiceImpl(); //被代理对象 UserServiceProxyFactory userServiceProxyFactory = new UserServiceProxyFactory(us); UserService user = userServiceProxyFactory.getUserServiceProxy(); //获取代理对象 user.save(); //调用方法 } } ~~~ ### 1.2 cglib代理 ~~~ package cn.itcast.c_proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import cn.itcast.service.UserService; import cn.itcast.service.UserServiceImpl; //观光代码=>cglib代理 public class UserServiceProxyFactory2 implements MethodInterceptor { public UserService getUserServiceProxy(){ Enhancer en = new Enhancer();//帮我们生成代理对象 en.setSuperclass(UserServiceImpl.class);//设置对谁进行代理 en.setCallback(this);//代理要做什么 UserService us = (UserService) en.create();//创建代理对象 return us; } @Override public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable { //打开事务 System.out.println("打开事务!"); //调用原有方法 Object returnValue = methodProxy.invokeSuper(prxoyobj, arg); //提交事务 System.out.println("提交事务!"); return returnValue; } } ~~~ ### 1.3 名词解释 ![](https://box.kancloud.cn/7f3678e465945d45b677399bc775a5f2_870x493.png) ### 1.4 spring AOP #### 1.4.1 xml AOP 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: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/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.aixin.bean"></context:component-scan> <!-- 1. 配置目标对象 --> <bean name="userService" class="com.aixin.daili.UserServiceImpl"></bean> <!-- 2. 配置通知对象 --> <bean name="myAdvice" class="com.aixin.c_proxy.MyAdvice"></bean> <!-- 3. 配置将通知组织入对象 --> <aop:config> <!-- 1. 配置切点 public void com.aixin.daili.UserServiceImpl.save())" public 可省略 * 代替返回值 空参 * com.aixin.daili.UserServiceImpl.*() * com.aixin.daili.UserServiceImpl.*(..) 不要求参数 * com.aixin.daili.*ServiceImpl.*(..) 不要求参数,所有ServiceImpl .. 表示子包和子包的所有包 --> <aop:pointcut id="pc" expression="execution(* com.aixin.daili.*ServiceImpl.*(..))"></aop:pointcut> <aop:aspect ref="myAdvice"> <aop:before method="before" pointcut-ref="pc"/> <aop:after method="afterRunning" pointcut-ref="pc"/> <aop:around method="around" pointcut-ref="pc"/> <aop:after-throwing method="afterException" pointcut-ref="pc"/> <aop:after method="after" pointcut-ref="pc"/> </aop:aspect> </aop:config> </beans> ~~~ 通知类 ~~~ package com.aixin.c_proxy; import org.aspectj.lang.ProceedingJoinPoint; /** * Created by dailin on 2017/12/12. * 通知类 */ public class MyAdvice { //前置通知 // |-目标方法执行前调用 //后置通知 (如果出现异常不会调用) // |-目标方法执行后调用 //环绕通知 // |-目标方法执行前后都调用 //异常拦截通知 // |-如果出现异常调用 //后置通知(无论是否出现 异常都会调用 // |-目标方法运行后 //前置通知 public void before(){ System.out.println("前置通知。。。"); } //后置通知 public void afterRunning(){ System.out.println("后置通知(如果出现异常不会调用)。。。"); } public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕通知前。。。"); Object proceed = pjp.proceed(); System.out.println("环绕通知后。。。"); return proceed; } public void afterException(){ System.out.println("出现异常。。。"); } //后置通知 public void after(){ System.out.println("后置通知。。。"); } } ~~~ #### 1.4.2 注解式AOP ~~~ //通知类 @Aspect //表示该类是一个通知类 public class MyAdvice { // 这样就不用每个通知都要写切入点表达式了 @Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))") public void pc(){} //前置通知 //指定该方法是前置通知,并制定切入点 @Before("MyAdvice.pc()") public void before(){ System.out.println("这是前置通知!!"); } //后置通知 @AfterReturning("execution(* cn.itcast.service.*ServiceImpl.*(..))") public void afterReturning(){ System.out.println("这是后置通知(如果出现异常不会调用)!!"); } //环绕通知 @Around("execution(* cn.itcast.service.*ServiceImpl.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("这是环绕通知之前的部分!!"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("这是环绕通知之后的部分!!"); return proceed; } //异常通知 @AfterThrowing("execution(* cn.itcast.service.*ServiceImpl.*(..))") public void afterException(){ System.out.println("出事啦!出现异常了!!"); } //后置通知 @After("execution(* cn.itcast.service.*ServiceImpl.*(..))") public void after(){ System.out.println("这是后置通知(出现异常也会调用)!!"); } } ~~~ ## 2. 三种对象创建方式 ### 2.1 三种方式 ~~~ <?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"> <!-- 创建方式1:空参构造 --> <bean name="user" class="com.aixin.bean.User"></bean> <!-- 创建方式2:静态工厂创建,由静态工厂类创建对象并放入容器 --> <bean name="user2" class="com.aixin.bean.UserFactory" factory-method="createUser"></bean> <!-- 创建方式3:实例工厂对象创建 调用userfactory对象创建对象 --> <bean name="user3" factory-bean="userfactory" factory-method="createUser2"></bean> <bean name="userfactory" class="com.aixin.bean.UserFactory"></bean> </beans> ~~~ ### 2.2 scope 控制对象(bean)的数量 ![](https://box.kancloud.cn/810c968474c2122c650d476bd8fb9457_520x193.png) ## 3. 属性注入 ~~~ public class User { public User() { System.out.println("User对象空参构造方法!!!!"); } private String name; private Integer age; private Car car; public User(String name, Car car) { System.out.println("User(String name, Car car)!!"); this.name = name; this.car = car; } public User(Car car,String name) { System.out.println("User(Car car,String name)!!"); this.name = name; this.car = car; } public User(Integer name, Car car) { System.out.println("User(Integer name, Car car)!!"); this.name = name+""; this.car = car; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } 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 void init(){ System.out.println("我是初始化方法!"); } public void destory(){ System.out.println("我是销毁方法!"); } @Override public String toString() { return "User [name=" + name + ", age=" + age + ", car=" + car + "]"; } } ~~~ ### 3.1 set方法注入属性 ~~~ <!-- set方式注入: --> <bean name="user" class="cn.itcast.bean.User" > <!--值类型注入: 为User对象中名为name的属性注入tom作为值 --> <property name="name" value="tom" ></property> <property name="age" value="18" ></property> <!-- 引用类型注入: 为car属性注入下方配置的car对象 --> <property name="car" ref="car" ></property> </bean> <!-- 将car对象配置到容器中 --> <bean name="car" class="cn.itcast.bean.Car" > <property name="name" value="兰博基尼" ></property> <property name="color" value="黄色" ></property> </bean> ~~~ ### 3.2 构造函数 > name属性: 构造函数的参数名 > index属性: 构造函数的参数索引 > type属性: 构造函数的参数类型 ~~~ <!-- 将car对象配置到容器中 --> <bean name="car" class="cn.itcast.bean.Car" > <property name="name" value="兰博基尼" ></property> <property name="color" value="黄色" ></property> </bean> <!-- ============================================================ --> <!-- 构造函数注入 --> <bean name="user2" class="cn.itcast.bean.User" > <!-- name属性: 构造函数的参数名 --> <!-- index属性: 构造函数的参数索引 --> <!-- type属性: 构造函数的参数类型--> <constructor-arg name="name" index="0" type="java.lang.Integer" value="999" ></constructor-arg> <constructor-arg name="car" ref="car" index="1" ></constructor-arg> </bean> ~~~ ### 3.3 p名称空间注入 p名称空间注入, 走set方法 1.导入P名称空间 xmlns:p="http://www.springframework.org/schema/p" 2.使用p:属性完成注入 |-值类型: p:属性名="值" |-对象类型: p:属性名-ref="bean名称" ~~~ <bean name="user3" class="cn.itcast.bean.User" p:name="jack" p:age="20" p:car-ref="car" > </bean> ~~~ ### 3.4 spel注入 spel注入: spring Expression Language sping表达式语言 <bean name="user4" class="cn.itcast.bean.User" > <property name="name" value="#{user.name}" ></property> <property name="age" value="#{user3.age}" ></property> <property name="car" ref="car" ></property> </bean> ## 4. 注解注入 context 扫描包 ~~~ <?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.aixin.bean"></context:component-scan> </beans> ~~~ 1. 创建对象 ~~~ //@Component("user") // @Service("user") // service层 // @Controller("user") // web层 @Repository("user")// dao层 ~~~ 2. 属性自动注入 ~~~ //@Autowired //自动装配 //问题:如果匹配多个类型一致的对象.将无法选择具体注入哪一个对象. ~~~ * 自动选择注入 3. 初始化与销毁(销毁得是单例) ~~~ @PostConstruct //在对象被创建后调用.init-method @PreDestroy //在销毁之前调用.destory-method ~~~ ~~~ @Autowired @Qualifier("car2") //@Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象 ~~~ ~~~ package cn.itcast.bean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import javax.xml.ws.RespectBinding; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; //<bean name="user" class="cn.itcast.bean.User" /> //@Component("user") // @Service("user") // service层 // @Controller("user") // web层 @Repository("user")// dao层 //指定对象的作用范围 @Scope(scopeName="singleton") public class User { private String name; @Value("18") private Integer age; //@Autowired //自动装配 //问题:如果匹配多个类型一致的对象.将无法选择具体注入哪一个对象. //@Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象 @Resource(name="car")//手动注入,指定注入哪个名称的对象 private Car car; public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } public String getName() { return name; } @Value("tom") public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @PostConstruct //在对象被创建后调用.init-method public void init(){ System.out.println("我是初始化方法!"); } @PreDestroy //在销毁之前调用.destory-method public void destory(){ System.out.println("我是销毁方法!"); } @Override public String toString() { return "User [name=" + name + ", age=" + age + ", car=" + car + "]"; } } ~~~ #### 注解 ~~~ package com.bean; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * Created by dailin on 2017/12/13. */ @Component //根据类名生成以类名首字母小写的对象 public class Car { private String name; private String color; public String getName() { return name; } public void setName(String name) { this.name = name; } } ~~~ 把car注入到人 ~~~ package com.bean; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * Created by dailin on 2017/12/13. */ @Component("user") //给对象起名,不起按照类首字母小写规则生成对象 public class User { private Integer id; private String name; @Resource private Car car; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } @Override public String toString() { return getName()+getCar(); } } ~~~ 测试 ~~~ public class test { @org.junit.Test public void test(){ ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application2.xml"); User us = (User) classPathXmlApplicationContext.getBean("user"); System.out.println(us); } } ~~~ 得到 ~~~ nullcom.bean.Car@19dc67c2 ~~~