注解名称 | 解释 |
---|---|
@Component | 实例化Bean,默认名称为类名收字母变小写。支持自定义名称 |
@Repository | @Component子标签。作用和@Component一样。用在持久层 |
@Service | @Component子标签。作用和@Component一样。用在业务层 |
@Controller | @Component子标签。作用和@Component一样。用在控制器层 |
@Configuration | @Component子标签。作用和@Component一样。用配置类 |
@Autowired | 自动注入。默认byType,如果多个同类型bean,使用byName(默认通过属性名查找是否有同名的bean,也可以通过@Qualifier("bean名称"),执行需要注入的Bean名称) |
@Resource | 非Spring注解。默认byName,如果没找到,使用byType。 |
(1)在applicationContext.xml(Spring的xml文件)中的头文件中添加xmlns:context的xsd规范。
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">
(2)在该文件中配置希望被扫描的包
(3)在想要的类上添加注解,相当与
@Component
(4)在想要注入的属性添加注解
@Autowired
普通测试使用
(1)导入junit依赖
junit
junit
4.13.2
test
(2)写一个随意名称的public void 修饰并且空参的方法,并添加@Test注解
Spring整合Test
(1)导入spring-test依赖
org.springframework
spring-test
5.3.23
test
(2)给测试类添加注解
// 使用Spring整合Junit4的类启动当前测试类
@RunWith(SpringJUnit4ClassRunner.class)
// 启动时加载的配置文件,里面要包含classpath
@ContextConfiguration(locations = "classpath:applicatonContext.xml")
(1)AOP作用:在不修改原有代码的基础上,对方法的功能进行扩充。
(2)相关概念:
Aspect:切面。即join point + Advice
join point: 切入点。就是我们平时说的目标方法,或说对哪个方法做扩展,做增强。
Advice:通知,增强内容。
Pointcut:切点。就是表达式,通过表达式说明哪些方法是join point
AOP Proxy:代理。Spring支持JDK动态代理和cglib动态代理两种方式,可以通过proxy-target-class=true把默认的JDK动态代理修改为Cglib动态代理。
Weaving:织入。织入就是把Advice添加到join point的过程。
(3)在Spring中提供了两种方式实现AOP:
Schema-based: 所有的通知都需要实现特定类型的接口。
AspectJ:可以使用普通Java类结合特定的配置标签实现通知。
(1)通知分类
前置通知:在切入点之前执行的增强功能。通知需要实现MethodBeforeAdvice接口
后置通知:在切入点之后执行的增强功能。通知需要实现AfterReturningAdvice接口
环绕通知:一个方法包含了前置通知和后置通知的功能。通知需要实现MethodInterceptor接口
异常通知:如果切入点中出现了异常(绝对不能try...catch解决了异常)就会触发异常通知。通知需要实现ThrowsAdvice接口。
(2)使用方式
1.导入aspectjweaver依赖
org.aspectj
aspectjweaver
1.9.9.1
2.定义通知类并实现相应的接口,并重写方法
package com.bjsxt.aop;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyBefore implements MethodBeforeAdvice {
/**
* @param method 切入点 目标方法
* @param args 切入点的参数
* @param target 切入点所在的类对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置通知执行了");
}
}
3.将切入点类和通知类放到spring容器中,并将切入点类设置到切点中,最后将通知类织入到切入点中。
4.其他通知使用方法类似。
特殊的有
1.环绕通知的参数为 MethodInvocation invocation 可以通过该参数调用切入点方法,invocation.proceed();
2.异常通知的接口中没有需要重写的方法但是必须写一个
public void afterThrowing(Exception e){}的类,返回值可以改变,其他的不能改变。
(1)创建通知类
package com.bjsxt.advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
//前置通知方法
public void before(){
System.out.println("我是前置通知方法...");
}
//后置通知方法
public void after(){
System.out.println("我是后置通知方法...");
}
//环绕通知方法
public Object round(ProceedingJoinPoint pp) throws Throwable {
System.out.println("环绕---前");
//放行
Object proceed = pp.proceed();
System.out.println("环绕---后");
return proceed;
}
//异常通知方法
public void myThrow(Exception ex){
System.out.println("我是异常通知......"+ex.getMessage());
}
}
(2)配置AOP
(3)有参数的配置
(1)在spring容器文件中让AOP注解生效
(2)@Aspect
作用:声明该类为通知类
使用:结合@Component在通知类上使用
(3)@Pointcut("execution(* com.bjsxt.service.impl.UserServiceImpl.testMethod())")
作用:声明切点
使用:在切点方法上使用
(4)通知织入
@Before("com.bjsxt.service.impl.UserServiceImpl.testMethod()")
作用:声明方法为前置通知方法
使用:在前置通知方法上声明
@After
@AfterReturning("com.bjsxt.service.impl.UserServiceImpl.testMethod()")
作用:声明方法为后置通知方法
使用:在后置通知方法上声明
@Around
@Around("com.bjsxt.service.impl.UserServiceImpl.testMethod()")
作用:声明方法为环绕通知方法
使用:在环绕通知方法上声明
@AfterThrowing
@AfterThrowing(value = "com.bjsxt.service.impl.UserServiceImpl.testMethod()",throwing = "e")
作用:声明方法为异常通知方法
使用:在异常通知方法上声明
(1)静态代理:代理对象由程序员自己编写!
(2)动态代理: 代理对象是动态生产的!动态代理又分为JDK动态代理和Cglib动态代理两种实现方式。其中JDK动态代理是基于接口实现,也就是代理对象和真实对象需要实现相同的接口,JDK动态代理是Java官方提供的技术。Cglib动态代理是基于继承实现的,也就是代理对象需要继承真实对象,Cglib动态代理是第三方的技术,使用的时候需要导入jar包。
JDK的动态代理,基于反射
package com.bjsxt.adv;
public interface Service {
void test();
}
被代理类
package com.bjsxt.adv.impl;
import com.bjsxt.adv.Service;
public class ServiceImpl implements Service {
@Override
public void test() {
System.out.println("test");
}
}
代理类
package com.bjsxt.adv;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyAdvice implements InvocationHandler {
public Object object;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理前置");
Object invoke = method.invoke(object, args);
System.out.println("动态代理后置");
return invoke;
}
}
使用类
package com.bjsxt.adv.impl;
import com.bjsxt.adv.MyAdvice;
import com.bjsxt.adv.Service;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
MyAdvice myAdvice = new MyAdvice();
myAdvice.object = new ServiceImpl();
Service service = (Service) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Service.class}, myAdvice);
service.test();
}
}
cglib的动态代理,基于继承
package com.bjsxt.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("后置");
return o1;
}
}
package com.bjsxt.cglib;
import com.bjsxt.adv.impl.ServiceImpl;
import net.sf.cglib.proxy.Enhancer;
public class CglibTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(new CglibProxy());
enhancer.setSuperclass(ServiceImpl.class);
ServiceImpl service = (ServiceImpl) enhancer.create();
service.test();
}
}