=====================================================================================
调用者和被调用者都需要有Spring创建
见3.5板块
<?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">
//StuDao接口
public interface StuDao {
public String sayHello (String name);
}
//接口实现类
public class StuDaoImpl implements StuDao{
public String sayHello(String name) {
String str = “HelloWord” + name;
return str;
}
}
在service实现类中添加StuDao类型的成员变量,并添加setter方法
//CustomService接口
public interface CustomService {
public String helloCustom(String name);
}
//接口实现类
public class CustomServiceImpl implements CustomService{
//创建对象并生成set方法
private StuDao stuDao;
public void setStuDao(StuDao stuDao){
this.stuDao=stuDao;
}
@Override
public String helloCustom(String name) {
String s = stuDao.sayHello(name);
return s;
}
}
5.5 在spring.xml中注册dao和service实现类
<?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">
在测试类中获取spring上下文
public class Demo3Test {
@Test
public void test3Spring(){
//获取spring容器的上下文对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“classpath:spring.xml”);
//从spring上下文中获取service对象
CustomService customService = (CustomService)applicationContext.getBean(“CustomService”);
String s = customService.helloCustom(“kaka”);
System.out.println(s);
}
}
=================================================================================
- 默认情况下 scope取值为singleton (单例) spring管理自己创建的对象生命周期,地址值不会改变;
- 当scope设为prototype时spring将按照多例创建对象,会改变地址;
步骤见第三板块(创建web项目)
org.springframework
spring-context
4.3.6.RELEASE
<?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”>
在entity包下
package com.sx.kak.entity;
/**
- Created by Kak on 2020/8/11.
*/
public class Student {
private int id;
private String name;
private String sex;
private String age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Student(int id, String name, String sex, String age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
public Student() {
}
}
在测试文件夹下的对应目录
package com.sx.kak.entity;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- Created by Kak on 2020/8/11.
*/
public class TestStudent {
@Test
public void test1(){
Student student = new Student();
//手动new对象
System.out.println(“手动创建:”+student);
//从spring获得new对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:spring.xml”);
Student student1 = (Student) context.getBean(“student”);
System.out.println(“spring创建01:”+student1);
//从spring再次获取对象
Student student2 = (Student) context.getBean(“student”);
System.out.println(“spring创建02:”+student2);
}
}
- 当scope取值为singleton(默认) ,spring管理自己创建的对象生命周期,地址值不会改变;
7. Spring核心_IOC(控制反转)&DI(依赖注入)
===================================================================================================
IOC(inverse of controll)是在程序代码编译之先就已经确立相互间的依赖关系 (由代码控制的依赖关系),将对象的创建由容器(spring)完成,事先不知道所对应的对象,只有执行到对应的位置才可以知道对应的对象,在运行时动态由容器注入给依赖着,由此确定相互间依赖关系称为IOC;
解决了具有耦合关系之间的强耦合;
- 由代码控制的依赖关系在编译之初已经确立
- 由运行时动态的容器注入实现的依赖关系
DI (dependency injection)依赖注入,编译的时候不知道,只有在运行时由容器动态的注入;就是在spring创建时为对应的属性赋值;
注意:IOC就是DI,DI就是IOC
<?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”>
package com.sx.kak.entity;
/**
- Created by Kak on 2020/8/11.
*/
public class Student {
private int id;
private String name;
private String sex;
private String age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Student(int id, String name, String sex, String age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
public Student() {
}
}
package com.sx.kak.dao;
import com.sx.kak.entity.Student;
/**
- Created by Kak on 2020/8/11.
*/
public class StuDao {
private Student student;
public void setStudent(Student student){
this.student = student;
}
//此处不知道对象是student01还是student01,只有在运行时才知道
public void sayHello(){
System.out.println(“student:【”+student.getId()+“\t”+student.getName()+“\t”+student.getSex()+“\t”+student.getAge()+“】”);
}
}
package com.sx.kak.entity;
import com.sx.kak.dao.StuDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- Created by Kak on 2020/8/11.
*/
public class TestStudent {
@Test
public void test1(){
//从spring获得new对象
ApplicationContext context = new ClassPathXmlApplicationContext(“classpath:spring.xml”);
//直接得到Student的对象
Student student01 = context.getBean(“student01”, Student.class);
System.out.println(student01.getId()+“\t”+student01.getName()+“\t”+student01.getSex()+“\t”+student01.getAge());
Student student02 = context.getBean(“student02”, Student.class);
System.out.println(student02.getId()+“\t”+student02.getName()+“\t”+student02.getSex()+“\t”+student02.getAge());
//依赖student01
//IOC原理:运行时动态的由spring给StuDao注入对象,(spring内核有两对象)注入只有在运行时生效
StuDao stuDao = context.getBean(StuDao.class);
stuDao.sayHello();
}
}
- 运行时动态的由spring给StuDao注入对象,(spring内核有两对象)注入只有在运行时生效
两种搜索机制
- 按照名称搜索
- 按照类型搜索
============================================================================
常见于在spring上下文中的属性,使用value节点(设值注入的特例)
- 前提条件:有同名的成员变量,及setter方法
成员变量私有,有setter方法,设值注入需要确保被spring创建的类含有无参构造器;
8.2.1 直接赋值则使用value属性完成
8.3.2 注入的是另外一个spring管理的对象
8.3.2.1使用ref完成(常用)
8.3.2.2 使用bean完成
当对象依赖需要明确先后顺序,被注入的对象一定先于注入产生
8.3.1 编写含有构造器的StuDao
package com.sx.kak.dao;
import com.sx.kak.entity.Student;
/**
- Created by Kak on 2020/8/11.
*/
public class StuDao2 {
private Student student;
public StuDao2(Student student){
this.student = student;
}
public void sayHello(){
System.out.println(“student:【”+student.getId()+“\t”+student.getName()+“\t”+student.getSex()+“\t”+student.getAge()+“】”);
}
}
8.3.2 配置spring.xml文件
8.3.3 编写测试类
package com.sx.kak.entity;
import com.sx.kak.dao.StuDao2;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- Created by Kak on 2020/8/11.
*/
public class TestStudent_02 {
@Test
public void test1(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“spring.xml”);
StuDao2 bean = context.getBean(StuDao2.class);
bean.sayHello();
}
}
8.3.4 构造子注入按照形参名称注入
8.3.5 构造子注入按照形参下标顺序注入
- 使用场景不同,前者在对象生产顺序有严格要求时必须采纳;后者对对象生产顺序不敏感可采纳;
- 实现方式不同:前者需要以成员变量的类型作为构造器的参数类型 ;后者需要对成员变量有setter方法
==================================================================================
本板块用到的依赖
junit
junit
4.11
test
org.springframework
spring-context
4.3.6.RELEASE
org.springframework
spring-aspects
4.3.6.RELEASE
cglib
cglib
3.3.0
org.springframework
spring-aop
4.3.6.RELEASE
AOP(Aspect Oriented Programming)切面编程,AOP是将分散在各处的相同业务集中管理的编程方式;AOP的优势是代码高可用、高复用、后期维护方便;是spring的核心基石;
- Spring的AOP编程即是通过动态代理类为原始类的方法添加辅助功能;
- 连接点(Joinpoint):连接点是程序类中的客观存在的方法,可被Spring拦截并切入内容;
- 切入点(Pointcut):被Spring切入连接点;
- 通知、增强(Advice):可以为切入点添加额外功能(前置通知、后置通知、异常通知、环绕通知);
- 目标对象(Target):代理的目标对象;
- 引介(Introduction):一种特殊的增强,可在运行期间为类动态的添加Filed和Method;
- 织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程;
- 代理(Proxy):被AOP织入通知后,产生的结果类;
- 切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点;
将核心功能与辅助功能(事务、日志等等)分离,实现辅助业务代码的复用;(案例场景:模拟计算机)
9.3.1 没有使用代理模式
缺点:
- 工作量大,如果项目中有多个类或者多个方法需要修改多次;
- 违背了开闭原则,对扩展开放,对修改关闭,而为了增加功能把每个方法都修改了,不便于维护;
- 违背了单一职责,每个方法除了要完成自己本身的功能,还要计算耗时、延时;
- 违背了依赖倒转,抽象不应该依赖细节,两者都应该依赖抽象;
package com.sx.kak.demo01;
/**
-
定义了四个方法
-
Created by Kak on 2020/8/11.
*/
public class Calculator {
public int plus(int a, int b){
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
package com.sx.kak.demo01;
import java.util.Random;
/**
-
继承Calculator中的方法(修改了方法)
-
Created by Kak on 2020/8/11.
*/
public class StaticProxy extends Calculator{
public int plus(int a,int b){
long begin = System.currentTimeMillis();
int result = a + b;
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
public int minus(int a,int b){
long begin = System.currentTimeMillis();
int result = a - b;
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
public int multi(int a,int b){
long begin = System.currentTimeMillis();
int result = a * b;
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
public int div(int a,int b){
long begin = System.currentTimeMillis();
int result = a / b;
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
public void sleeping(){
Random random = new Random(1000);
try {
Thread.sleep(random.nextInt());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
9.3.2 静态代理设计模式
通过代理类的对象,为原始类的对象添加辅助功能,更加容易更换代理实现类,利于维护;
条件:
- 必须要有接口;
- 单一职责
9.3.2.1 创建IMath接口
package com.sx.kak.demo02;
/**
-
接口调用Calculator
-
父类接口指向子类实现
-
Created by Kak on 2020/8/11.
*/
public interface IMath {
public int plus(int a ,int b);
public int minus(int a ,int b);
public int multi(int a ,int b);
public int div(int a ,int b);
}
9.3.2.2 创建Calculator实现IMath接口
package com.sx.kak.demo02;
/**
- Created by Kak on 2020/8/11.
*/
public class Calculator implements IMath{
public int plus(int a, int b){
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
9.3.2.3 创建StaticProxy.java实现IMath
静态代理类由原始类的接口加辅助功能加原始类的业务方法组成
package com.sx.kak.demo02;
import java.util.Random;
/**
- Created by Kak on 2020/8/11.
*/
public class StaticProxy implements IMath{
private IMath math;
public StaticProxy(IMath math){
this.math = math;
}
@Override
public int plus(int a, int b) {
long begin = System.currentTimeMillis();
int result = math.plus(a,b);
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
@Override
public int minus(int a, int b) {
long begin = System.currentTimeMillis();
int result = math.minus(a,b);
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
@Override
public int multi(int a, int b) {
long begin = System.currentTimeMillis();
int result = math.multi(a,b);
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
@Override
public int div(int a, int b) {
long begin = System.currentTimeMillis();
int result = math.div(a,b);
this.sleeping();
long end = System.currentTimeMillis();
System.out.println(“方法耗时:”+(end - begin));
return result;
}
public void sleeping(){
Random random = new Random(1000);
try {
Thread.sleep(random.nextInt());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
9.3.2.4 静态代理优缺点
优点:
- 解决了开闭原则,没有修改Calculator类,扩展出了StaticProxy类
- 解决了单一职责的问题,Calculator类不再需要去计算耗时与延时操作;
- 引入接口解决了依赖倒转问题;
优点:
- 如果项目中有多个类,则需要编写多个代理类,工作量大,不好修改,不能应对变化,维护性差;
9.3.3 动态代理设计模式_ jdk代理
动态创建代理类,为原始类的对象添加辅助功能;
- 只能代理有接口的实现
- 使用Proxy 接口API
9.3.3.1 创建IMath接口
package com.sx.kak.demo03;
/**
-
接口调用Calculator
-
父类接口指向子类实现
-
Created by Kak on 2020/8/11.
*/
public interface IMath {
public int plus(int a, int b);
public int minus(int a, int b);
public int multi(int a, int b);
public int div(int a, int b);
}
9.3.3.2 创建Calculator实现IMath接口
package com.sx.kak.demo03;
/**
- Created by Kak on 2020/8/11.
*/
public class Calculator implements IMath{
public int plus(int a, int b){
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
9.3.3.3 创建DynamicProxy加入动态代理实现InvocationHandler接口
package com.sx.kak.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Random;
/**
-
JDK动态代理
-
Created by Kak on 2020/8/11.
*/
public class DynamicProxy implements InvocationHandler{
Object targetObject;
public Object getObject(Object SrcObject){
this.targetObject = SrcObject;
//获取代理对象
/**
-
作用:使用动态代理自动给正在执行的对象的接口生成一个新的派生对象,此对象还有invoke方法中附带的逻辑
-
第一个参数:需要执行方法的对象的类加载器
-
第二个参数:需要执行方法的对象实现的接口
-
第三个参数:InvocationHandler的实现对象
*/
Object o = Proxy.newProxyInstance(SrcObject.getClass().getClassLoader(),SrcObject.getClass().getInterfaces(),this);
return o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long begin = System.currentTimeMillis();
sleeping();
//执行原有的方法
/**
-
第一个参数:方法所在的对象
-
第二个参数:方法执行的实参
*/
Object result = method.invoke(targetObject,args);
long end = System.currentTimeMillis();
System.out.println(“方法耗时:” + (end - begin));
return result;
}
public void sleeping(){
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
9.3.3.4 创建测试类
package com.sx.kak.demo03;
/**
- Created by Kak on 2020/8/11.
*/
public class TestCalculator {
public static void main(String[] args) {
//源对象
Calculator cal = new Calculator();
//自定义的附带有计算耗时的动态代理
DynamicProxy proxy = new DynamicProxy();
IMath newObj = (IMath)proxy.getObject(cal);
int plus = newObj.plus(1, 10);
System.out.println(plus);
}
}
9.3.3.4 JDK动态代理的优缺点
优势:
- 解决了静态代理存在的问题
- JDK内置的Proxy动态代理可以在运行时动态生成字节码,而没必要针对每个类编写代理类;使用到了一个接口InvocationHandler与Proxy.newProxyInstance静态方法;
劣势:
- 被代理的类必须实现接口,未实现接口则没办法完成动态代理。
9.3.4 动态代理设计模式_ cglib代理
CGLIB(Code Generation Library)是一个开源项目,高性能,高质量的Code生成类库,可以在运行时动态生成字节码;
- cglib继承被代理的类,重写方法,织入通知,动态生成字节码并运行(动态的生成一个子类去覆盖所要代理的类);
- 因为是继承所以final类是没有办法动态代理的;
- 必须引入cglib的jar包;
- 不需要接口可以在运行时,动态生成新的派生匿名对象从而附加新的功能;
Enhancer允许为非接口类型创建一个JAVA代理,Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法;
9.3.4.1 编写Calculator.java需要被代理的类
package com.sx.kak.demo04;
/**
- Created by Kak on 2020/8/11.
*/
public class Calculator {
public int plus(int a, int b){
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
9.3.4.2 编写DynamicProxy.java实现cglib代理
package com.sx.kak.demo04;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Random;
/**
- Created by Kak on 2020/8/11.
*/
public class DynamicProxy implements MethodInterceptor{
Object targetObj;
public Object getObject(Object srcObj){
this.targetObj = srcObj;
//创建代码增强器
Enhancer enhancer = new Enhancer();
//设定增强器的父类
enhancer.setSuperclass(srcObj.getClass());
//设定增强器回调对象
enhancer.setCallback(this);
//获取附加逻辑的新对象
Object o = enhancer.create();
return o;
}
/**
-
@param o 需要代理的对象
-
@param method 需要执行的方法
-
@param objects 执行方法所需要的实参
-
@param methodProxy 代理的对象
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long begin = System.currentTimeMillis();
sleeping();
Object invoke = method.invoke(targetObj, objects);
long end = System.currentTimeMillis();
System.out.println(“耗时:”+ (end - begin));
return invoke;
}
public void sleeping(){
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
9.3.4.3 编写测试类
package com.sx.kak.demo04;
/**
- Created by Kak on 2020/8/11.
*/
public class TestCglib {
public static void main(String[] args) {
Calculator newObj = (Calculator)new DynamicProxy().getObject(new Calculator());
int minus = newObj.minus(20, 30);
System.out.println(minus);
}
}
- ProxyFactory
9.4.1 被代理类
package com.sx.kak.demo05;
/**
- Created by Kak on 2020/8/11.
*/
public class Calculator {
public int plus(int a, int b){
System.out.println(“plus…”);
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
9.4.2 设置通知类
/**
-
前置通知
-
Created by Kak on 2020/8/11.
*/
public class BeforeAdviser implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(“前置通知…”);
}
}
/**
-
后置通知
-
Created by Kak on 2020/8/11.
*/
public class MyAfterAdviser implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(“后置通知…”);
}
}
/**
-
环绕通知
-
Created by Kak on 2020/8/11.
*/
public class MyRoundAdviser implements org.aopalliance.intercept.MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(“around before …”);
//执行原有逻辑
Object pro = invocation.proceed();
System.out.println(“around after …”);
return pro;
}
}
9.4.3 TestSpring.java测试
package com.sx.kak.demo05;
import org.springframework.aop.framework.ProxyFactory;
/**
-
Spring代理
-
Created by Kak on 2020/8/11.
*/
public class TestSpring {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
//给spring的代理工厂添加代理的原生对象
proxyFactory.setTarget(new Calculator());
//织入通知
//给代理工厂添加额外的通知对象
//前置通知
proxyFactory.addAdvice(new BeforeAdviser());
//添加一个后置通知
proxyFactory.addAdvice(new MyAfterAdviser());
//环绕通知
proxyFactory.addAdvice(new MyRoundAdviser());
//设值spring代理的模式:true—>cglib代理 false—>jdk代理
proxyFactory.setProxyTargetClass(true);
Calculator proxy = (Calculator)proxyFactory.getProxy();
int plus = proxy.plus(23, 34);
System.out.println(plus);
}
}
使用xml实现动态代理
9.5.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:p=“http://www.springframework.org/schema/p”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>
<bean id=“pf” class=“org.springframework.aop.framework.ProxyFactoryBean”
p:target-ref = “calcu”
p:interceptorNames=“beforeAdviser”
p:proxyTargetClass=“true”
9.5.2 被代理类
package com.sx.kak.demo06;
/**
- Created by Kak on 2020/8/11.
*/
public class Calculator{
public int plus(int a, int b){
System.out.println(“plus …”);
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
9.5.3 设置通知方法
package com.sx.kak.demo06;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
-
前置通知
-
Created by Kak on 2020/8/11.
*/
public class BeforeAdviser implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(“前置通知…”);
}
}
9.5.4 编写动态代理测试类
package com.sx.kak.demo06;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- Created by Kak on 2020/8/11.
*/
public class TestSpring {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“demo06/bean.xml”);
Calculator pf = (Calculator)context.getBean(“pf”);
int plus = pf.plus(23, 21);
System.out.println(plus);
}
}
定义通知类可以达到通知的效果;
- 前置通知:MethodBeforeAdvice
- 后置通知:AfterAdvice、AfterReturningAdvice(有异常不执行,无返回值,方法会因为异常而结束)
- 异常通知:ThrowsAdvice
- 环绕通知:MethodInterceptor
9.7.1 设置前置通知
package com.sx.kak.aop01;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
-
前置通知
-
Created by Kak on 2020/8/11.
*/
public class BeforeAdviser implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(“前置通知…”);
}
}
9.7.2 设置代理类
package com.sx.kak.aop01;
/**
- Created by Kak on 2020/8/11.
*/
public class Calculator {
public int plus(int a, int b){
System.out.println(“plus …”);
return a + b;
}
public int minus(int a, int b){
return a - b;
}
public int multi(int a, int b){
return a * b;
}
public int div(int a, int b){
return a / b;
}
}
9.7.3 配置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:p=“http://www.springframework.org/schema/p”
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/aop http://www.springframework.org/schema/aop/spring-aop.xsd”>
<aop:config proxy-target-class=“true”>
<aop:pointcut id=“poinyCut1” expression=“execution(* com.sx.kak.aop01.Calculator.*(…))”/>
<aop:advisor advice-ref=“beforeAdviser” pointcut-ref=“poinyCut1” />
</aop:config>
9.7.4 编写测试类
package com.sx.kak.aop01;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
-
spring-aop
-
Created by Kak on 2020/8/11.
*/
public class TestAop1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:aop01/bean.xml”);
Calculator bean = context.getBean(Calculator.class);
int plus = bean.plus(23, 89);
System.out.println(plus);
int div = bean.div(20, 5);
System.out.println(div);
}
}
9.8.1 设置前置通知
package com.sx.kak.aop01;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
-
前置通知
-
Created by Kak on 2020/8/11.
*/
public class BeforeAdviser implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(“前置通知…”);
}
}
9.8.2 设置代理类_Dog
package com.sx.kak.entity;
import org.springframework.stereotype.Component;
/**
- Created by Kak on 2020/8/11.
*/
@Component
public class Dog {
public void run(){
System.out.println(“Dog running …”);
}
public void bark(){
System.out.println(“Dog bark …”);
}
}
9.8.3 设置代理类_Person
package com.sx.kak.entity;
import org.springframework.stereotype.Component;
/**
- Created by Kak on 2020/8/11.
*/
//告诉spring容器把此类管理起来等同于bean配置
@Component
public class Person {
public void run(){
System.out.println(“Person running …”);
}
}
9.8.4 配置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:p=“http://www.springframework.org/schema/p”
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.sx.kak.entity”/>
<aop:config proxy-target-class=“true”>
<aop:pointcut id=“myp1” expression=“execution(* com.sx.kak.entity..(…))”/>
<aop:advisor advice-ref=“beforeAdviser” pointcut-ref=“myp1” />
</aop:config>
9.8.5 编写测试类
package com.sx.kak.entity;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
-
两个对象引用前置通知
-
Created by Kak on 2020/8/11.
*/
public class TestEntity {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:entity/bean.xml”);
Dog dog = context.getBean(Dog.class);
dog.run();
dog.bark();
Person per = context.getBean(Person.class);
per.run();
}
}
=============================================================================
本版块用到的依赖
junit
junit
4.11
test
org.springframework
spring-context
4.3.6.RELEASE
org.springframework
spring-aspects
4.3.6.RELEASE
简单java对象织入
- aop:config
- aop:before
- aop:after
10.1.1 创建被代理类
package com.sx.kak.aop03;
/**
-
代理对象_被代理类
-
Created by Kak on 2020/8/12.
*/
public class StuDao {
public void find(){
System.out.println(“代理对象”);
}
}
10.1.2 创建自定义通知类
package com.sx.kak.aop03;
import org.aspectj.lang.JoinPoint;
/**
-
简单Java类作为通知
-
Created by Kak on 2020/8/12.
*/
public class MyAdviser {
public void before(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(“before…” + methodName);
}
public void after(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(“after…” + methodName);
}
}
10.1.3 配置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”
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”>
<aop:config proxy-target-class=“true”>
<aop:aspect ref=“myAdviser”>
<aop:pointcut id=“ppl” expression=“execution(* com.sx.kak.aop03.StuDao.*(…))”/>
<aop:before method=“before” pointcut-ref=“ppl”/>
<aop:after method=“after” pointcut-ref=“ppl”/>
</aop:aspect>
</aop:config>
10.1.4 编写测试类
package com.sx.kak.aop03;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- Created by Kak on 2020/8/12.
*/
public class TestDamo03 {
@Test
public void test01(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:aop03/bean.xml”);
StuDao stuDao = context.getBean(StuDao.class);
stuDao.find();
}
}
注解模式:使用@Component +@Aspects
- 在通知方法前使用@Before 或@after 或@Around
10.2.1 创建被代理类
package com.sx.kak.aop04;
import org.springframework.stereotype.Component;
/**
-
代理对象_被代理类
-
Created by Kak on 2020/8/12.
*/
@Component
public class StuDao {
public void find(){
System.out.println(“代理对象”);
}
}
10.2.2 创建自定义通知类
package com.sx.kak.aop04;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
-
简单Java类作为通知
-
Created by Kak on 2020/8/12.
*/
//spring管理
@Component
//标识此类为一个切面类
@Aspect
public class MyAdviser {
//将此方法作为一个前置通知植入
@Before(value = “execution(* com.sx.kak.aop04.StuDao.*(…))”)
public void before(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(“before…” + methodName);
}
//将此方法作为一个后置通知植入
@After(value = “execution(* com.sx.kak.aop04.StuDao.*(…))”)
public void after(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(“after…” + methodName);
}
}
10.2.3 配置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/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.sx.kak.aop04”/>
<aop:aspectj-autoproxy proxy-target-class=“true”/>
10.2.4 编写测试类
package com.sx.kak.aop04;
import com.sx.kak.aop03.*;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
-
注解开发01
-
Created by Kak on 2020/8/12.
*/
public class TestDemo04 {
@Test
public void test01(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:aop04/bean.xml”);
StuDao stuDao = context.getBean(StuDao.class);
stuDao.find();
}
}
如果多个方法加通知,会显得繁琐,因此整合到一块,定义一个切点;
注解模式:使用@Component +@Aspects
- @PointCut 自定义切点
- @Before(切点函数)、@After 、@Around
10.3.1 创建被代理类
package com.sx.kak.aop05;
import org.springframework.stereotype.Component;
/**
-
代理对象_被代理类
-
Created by Kak on 2020/8/12.
*/
@Component
public class StuDao {
public void find(){
System.out.println(“查询成功”);
}
public void StuUpdateStu(){
System.out.println(“修改”);
}
public void StuDeleteStu(){
System.out.println(“删除”);
}
public void StuAddStu(){
System.out.println(“增加”);
}
}
10.3.2 创建自定义通知类
package com.sx.kak.aop05;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
-
简单Java类作为通知
-
Created by Kak on 2020/8/12.
*/
//spring管理
@Component
//标识此类为一个切面类
@Aspect
public class MyAdviser {
//自定义切点
@Pointcut(value = “execution(* com.sx.kak.aop05.StuDao.*(…))”)
public void pp1(){
}
//将此方法作为一个前置通知织入
@Before(“pp1()”)
public void before(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(“before…” + methodName);
}
//将此方法作为一个后置通知织入
@After(“pp1()”)
public void after(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(“after…” + methodName);
}
//自定义切点(非查询切入)
@Pointcut(“execution(* com.sx.kak.aop05.StuDao.*Stu(…))”)
public void pp2(){
}
@Around(“pp2()”)
public void around(ProceedingJoinPoint point)throws Throwable{
//执行方法本身
System.out.println(“around before…”);
point.proceed();
System.out.println(“around after…”);
}
}
10.3.3 创建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/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.sx.kak.aop05”/>
<aop:aspectj-autoproxy proxy-target-class=“true”/>
10.3.4 编写测试类
package com.sx.kak.aop05;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- Created by Kak on 2020/8/12.
*/
public class TestDemo05 {
@Test
public void test01(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:aop05/bean.xml”);
StuDao stuDao = context.getBean(StuDao.class);
stuDao.find();
stuDao.StuAddStu();
stuDao.StuUpdateStu();
stuDao.StuDeleteStu();
}
}
根据不同的需求切入的方法
<aop:pointcut id=“pointcuts” expression=“execution(* com.sx.kak.aop03.StuDao.*(…))”/>
<aop:pointcut id=“pointcuts” expression=“execution(* save())”/>
<aop:pointcut id=“pointcuts” expression=“execution(* save(…))”/>
<aop:pointcut id=“pointcuts” expression=“execution(* com.sx.kak.aop03.Student *(…))”/>
<aop:pointcut id=“pointcuts” expression=“execution(* com.sx.kak.aop03.StuDao.*(…))”/>
<aop:pointcut id=“pointcuts” expression=“execution(* com.sx.kak.aop03..(…))”/>
<aop:pointcut id=“pointcuts” expression=“execution(* com.sx.kak….(…))”/>
==============================================================================
<context:component-scan base-package=“com.sx.kak.controller”/>
<tx:annotation-driven transaction-manager=“txManager”/?
用于替换自建类型的<bean…>标签,快速的声明bean;