目录
1.2 配置注解扫描:指定扫描包下所有类中的注解,扫描包时,会扫描包所有的子孙包
1、注解实现IOC
1.1 配置文件中添加约束
参考文件位置:
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
1.2 配置注解扫描:指定扫描包下所有类中的注解,扫描包时,会扫描包所有的子孙包
<!--扫描包设置-->
<context:component-scan base-package="com.xzk.spring.bean"></context:component- scan>
1.3 注解
1.3.1 添加在类名上
@Component("对象名")
@Service("person") // service层
@Controller("person") // controller层
@Repository("person") // dao层
@Scope(scopeName="singleton") //单例对象
@Scope(scopeName="prototype") //多例对象
1.3.2 添加在属性上
@Value("属性值")
private String name;
@Autowired //如果一个接口类型,同时有两个实现类,则报错,此时可以借助@Qualifier("bean name")
@Qualifier("bean name")
private Car car; //说明:@Resource 是java的注释,但是Spring框架支持,@Resource指定注入哪个名称的对象
//@Resource(name="对象名") == @Autowired + @Qualifier("name")
@Resource(name="baoma")
private Car car;
1.3.3 添加在方法上
@PostConstruct //等价于init-method属性
public void init(){
System.out.println("初始化方法");
}
@PreDestroy //等价于destroy-method属性
public void destroy(){
System.out.println("销毁方法");
}
2、Aop介绍
Aop(Aspect Oriented Programming)即面向切面编程。即在不改变原程序的基础上为代码段增加新的功能。应用在权限认证、日志、事务。
Aop的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
2.1 AOP的实现机制
- JDK 的动态代理:针对实现了接口的类产生代理。InvocationHandler接口
- CGlib 的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强的技术 生成当前类的子类对象,MethodInterceptor接口
2.1.1 JDK动态代理实现
1. 创建接口和对应实现类
public interface UserService{
public void login();
}
// 实现类
public class UserServiceImpl implements UserService{
public void login();
}
2. 创建动态代理类,实现InvocationHandler接口
public class agency implements InvocationHandler {
private UserService target; //目标对象
public agency(UserService target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//本方法中的其他输出输入增强 //proxy 代理方法被调用的代理实例
System.out.println("方法触发了"); //执行被代理类 原方法
Object invoke = method.invoke(target, args);
System.out.println("执行完毕了");
return invoke;
}
}
// 测试
@Test
public void test1(){
//测试JDK动态代理技术
UserService us = new UserServiceImpl();
agency ag = new agency(us); //这里不能转换成一个实际的类,必须是接口类型
UserService uservice = (UserService)Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(),ag);
uservice.login();
}
测试结果:在调用接口方法的前后都会添加代理类的方法。
2.1.2 CGlib实现代理
> 使用JDK创建代理 有一个限制,它只能为接口创建代理实例。这一点可以从Proxy的接口方法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocarionHandler h)中看的很清楚
> 第二个入参interface 就是需要代理实例实现接口列表
> 对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK动态代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这一空缺。
> CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
添加依赖包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
1. 创建普通类
public class Users{
public void login(){}
}
2. 创建CGLib代理器
class CgProxy implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("输出语句1"); //参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法 //引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。
Object obj= methodProxy.invokeSuper(o,objects);
System.out.println("输出语句2");
return obj;
}
}
测试:
public static void main(String[] args) {
//1.创建真实对象
Users users = new Users();
//2.创建代理对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(users.getClass());
enhancer.setCallback(new CglibProxy());
Users o = (Users) enhancer.create();//代理对象
o.login();
}
结论:spring同时使用了这两种方式,底层会自行判断应该使用哪种
两种代理方式的区别:
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理final
关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方法直接调用委托类方法。
2.1.3 spring中使用aop
1、添加jar包
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
2、添加项目原有的调取过程
3、创建增强类(本质上就是一个普通类)
// 前置通知:目标方法运行之前调用 aop:before
// 后置通知(如果出现异常不会调用):在目标方法运行之后调用 apo:after-returning
// 环绕通知:在目标方法之前和之后都调用 apo:around
// 最终通知(无论是否出现 异常都会调用):在目标方法运行之后调用 aop:after
// 异常增强:程序出现异常时执行(要求:程序代码中不要处理异常)apo:after-throwing
环绕增强:
public Object around(ProceedingJoinPoint point) throws Throwable{
point.proceed();
}
4、添加aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
5、设置配置文件
<!--1.创建目标类对象-->
<bean name="userService" class="com.xzk.spring.service.UserServiceImpl" /> <!--2.配置增强类对象-->
<bean name="myAdvice" class="com.xzk.spring.aop.MyAdivce" />
<!-- 3.配置将增强织入目标对象-->
<aop:config>
<aop:pointcut id="pc"
expression="execution(* com.xzk.spring.service.ServiceImpl.*.* (..))"/>
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pc" />
<aop:after-returning method="afterReturning" 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>
注意:
1)环绕增强需要使用ProceedingJoinPoint作为参数
2)注意标签顺序